sme: Add SVE/SME testcases
authorLuis Machado <luis.machado@arm.com>
Mon, 10 Oct 2022 12:31:44 +0000 (13:31 +0100)
committerLuis Machado <luis.machado@arm.com>
Wed, 4 Oct 2023 15:23:40 +0000 (16:23 +0100)
Add 5 SVE/SME tests to exercise all the new features like reading/writing
registers, pseudo-registers, signal frames and core files.

- Sanity check for SME: Gives a brief smoke test to make sure the most basic
of features are working correctly.

- ZA unavailability tests: Validates the behavior/content of the ZA register
is correct when no payload is available.  It also exercises changing the
vector lengths.

- ZA availability tests: These tests exercise reading/writing to all the
possible ZA pseudo-registers, and validates the state is correct.

- Core file tests: Validates that core file reading and writing works
correctly and that all state dumped/loaded is sane.  This is exercised for
both Linux Kernel core files and gcore core files.

- Signal frame tests: Validates the correct restoration of SME/SVE/FPSIMD
values across signal frames.

Since some of these tests are very lengthy and take a little while to run
(under QEMU at the moment), I decided to parallelize them into smaller
chunks so we can throw some more CPU power at them so they run faster.

I'd still like to add a few more tests to give the testsuite more coverage
in the areas of SME/SVE.  Hopefully in the near future that will happen.

Just a reminder that these SME tests are currently unsupported when gdb is
connected to a remote target.  That's because the RSP doesn't support
communicating changes in vector lenghts mid-execution, so gdb will always
get wrong state from the remote target.

Co-Authored-By: Ezra Sitorus <ezra.sitorus@arm.com>
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
45 files changed:
gdb/testsuite/gdb.arch/aarch64-sme-core-0.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-core-1.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-core-2.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-core-3.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-core-4.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-core.c [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-core.exp.tcl [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-available-0.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-available-1.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-available-2.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-available-3.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-available-4.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-available-5.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-available-6.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-available-7.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-available-8.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-available-9.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-available.c [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-available.exp.tcl [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-0.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-1.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-2.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-3.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-4.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.c [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.exp.tcl [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-0.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-1.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-2.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-3.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-4.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-5.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-6.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-7.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-8.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-9.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.c [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.exp.tcl [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-sanity.c [new file with mode: 0644]
gdb/testsuite/gdb.arch/aarch64-sme-sanity.exp [new file with mode: 0644]
gdb/testsuite/lib/aarch64-scalable.exp [new file with mode: 0644]
gdb/testsuite/lib/aarch64-test-sme.c [new file with mode: 0644]
gdb/testsuite/lib/aarch64-test-sve.c [new file with mode: 0644]
gdb/testsuite/lib/aarch64.exp [new file with mode: 0644]
gdb/testsuite/lib/gdb.exp

diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-core-0.exp b/gdb/testsuite/gdb.arch/aarch64-sme-core-0.exp
new file mode 100644 (file)
index 0000000..5a51bbd
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# state: FPSIMD
+# VL: 16, 32, 64, 128, 256
+# SVL: 16, 32, 64, 128, 256
+# This set covers 25 (0 ~ 24) out of 125 tests.
+set id_start 0
+set id_end 24
+source $srcdir/$subdir/aarch64-sme-core.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-core-1.exp b/gdb/testsuite/gdb.arch/aarch64-sme-core-1.exp
new file mode 100644 (file)
index 0000000..41e93b1
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# state: SVE
+# VL: 16, 32, 64, 128, 256
+# SVL: 16, 32, 64, 128, 256
+# This set covers 25 (25 ~ 49) out of 125 tests.
+set id_start 25
+set id_end 49
+source $srcdir/$subdir/aarch64-sme-core.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-core-2.exp b/gdb/testsuite/gdb.arch/aarch64-sme-core-2.exp
new file mode 100644 (file)
index 0000000..05144d9
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# state: SSVE
+# VL: 16, 32, 64, 128, 256
+# SVL: 16, 32, 64, 128, 256
+# This set covers 25 (50 ~ 74) out of 125 tests.
+set id_start 50
+set id_end 74
+source $srcdir/$subdir/aarch64-sme-core.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-core-3.exp b/gdb/testsuite/gdb.arch/aarch64-sme-core-3.exp
new file mode 100644 (file)
index 0000000..fa8931a
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# state: ZA only
+# VL: 16, 32, 64, 128, 256
+# SVL: 16, 32, 64, 128, 256
+# This set covers 25 (75 ~ 99) out of 125 tests.
+set id_start 75
+set id_end 99
+source $srcdir/$subdir/aarch64-sme-core.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-core-4.exp b/gdb/testsuite/gdb.arch/aarch64-sme-core-4.exp
new file mode 100644 (file)
index 0000000..8881898
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# state: ZA + SSVE
+# VL: 16, 32, 64, 128, 256
+# SVL: 16, 32, 64, 128, 256
+# This set covers 25 (100 ~ 124) out of 125 tests.
+set id_start 100
+set id_end 124
+source $srcdir/$subdir/aarch64-sme-core.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-core.c b/gdb/testsuite/gdb.arch/aarch64-sme-core.c
new file mode 100644 (file)
index 0000000..d71d18e
--- /dev/null
@@ -0,0 +1,372 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2023 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Exercise AArch64's Scalable Vector/Matrix Extension core file generation
+   for GDB.  This includes reading Linux Kernel-generated core files and
+   writing GDB core files via the gcore command and making sure the contents
+   are sane.  */
+
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HWCAP_SVE
+#define HWCAP_SVE (1 << 22)
+#endif
+
+#ifndef HWCAP2_SME
+#define HWCAP2_SME (1 << 23)
+#endif
+
+#ifndef PR_SVE_SET_VL
+#define PR_SVE_SET_VL 50
+#define PR_SVE_GET_VL 51
+#define PR_SVE_VL_LEN_MASK 0xffff
+#endif
+
+#ifndef PR_SME_SET_VL
+#define PR_SME_SET_VL 63
+#define PR_SME_GET_VL 64
+#define PR_SME_VL_LEN_MASK 0xffff
+#endif
+
+static void
+enable_za ()
+{
+  /* smstart za */
+  __asm __volatile (".word 0xD503457F");
+}
+
+static void
+disable_za ()
+{
+  /* smstop za */
+  __asm __volatile (".word 0xD503447F");
+}
+
+static void
+enable_sm ()
+{
+  /* smstart sm */
+  __asm __volatile (".word 0xD503437F");
+}
+
+static void
+disable_sm ()
+{
+  /* smstop sm */
+  __asm __volatile (".word 0xD503427F");
+}
+
+static void
+initialize_fpsimd_state ()
+{
+  char buffer[16];
+
+  for (int i = 0; i < 16; i++)
+    buffer[i] = 0x55;
+
+  __asm __volatile ("mov x0, %0\n\t" \
+                   : : "r" (buffer));
+
+  __asm __volatile ("ldr q0, [x0]");
+  __asm __volatile ("ldr q1, [x0]");
+  __asm __volatile ("ldr q2, [x0]");
+  __asm __volatile ("ldr q3, [x0]");
+  __asm __volatile ("ldr q4, [x0]");
+  __asm __volatile ("ldr q5, [x0]");
+  __asm __volatile ("ldr q6, [x0]");
+  __asm __volatile ("ldr q7, [x0]");
+  __asm __volatile ("ldr q8, [x0]");
+  __asm __volatile ("ldr q9, [x0]");
+  __asm __volatile ("ldr q10, [x0]");
+  __asm __volatile ("ldr q11, [x0]");
+  __asm __volatile ("ldr q12, [x0]");
+  __asm __volatile ("ldr q13, [x0]");
+  __asm __volatile ("ldr q14, [x0]");
+  __asm __volatile ("ldr q15, [x0]");
+  __asm __volatile ("ldr q16, [x0]");
+  __asm __volatile ("ldr q17, [x0]");
+  __asm __volatile ("ldr q18, [x0]");
+  __asm __volatile ("ldr q19, [x0]");
+  __asm __volatile ("ldr q20, [x0]");
+  __asm __volatile ("ldr q21, [x0]");
+  __asm __volatile ("ldr q22, [x0]");
+  __asm __volatile ("ldr q23, [x0]");
+  __asm __volatile ("ldr q24, [x0]");
+  __asm __volatile ("ldr q25, [x0]");
+  __asm __volatile ("ldr q26, [x0]");
+  __asm __volatile ("ldr q27, [x0]");
+  __asm __volatile ("ldr q28, [x0]");
+  __asm __volatile ("ldr q29, [x0]");
+  __asm __volatile ("ldr q30, [x0]");
+  __asm __volatile ("ldr q31, [x0]");
+}
+
+static void
+initialize_za_state ()
+{
+  /* zero za */
+  __asm __volatile (".word 0xC00800FF");
+
+  char buffer[256];
+
+  for (int i = 0; i < 256; i++)
+    buffer[i] = 0xaa;
+
+  __asm __volatile ("mov x0, %0\n\t" \
+                   : : "r" (buffer));
+
+  /* Initialize loop boundaries.  */
+  __asm __volatile ("mov w12, 0");
+  __asm __volatile ("mov w17, 256");
+
+  /* loop: ldr za[w12, 0], [x0] */
+  __asm __volatile ("loop: .word 0xe1000000");
+  __asm __volatile ("add w12, w12, 1");
+  __asm __volatile ("cmp w12, w17");
+  __asm __volatile ("bne loop");
+}
+
+static void
+initialize_tpidr2 ()
+{
+  __asm __volatile ("mov x0, #0xffffffffffffffff");
+
+  /* Write x0 to tpidr2.  */
+  __asm __volatile (".word 0xd51bd0a0");
+}
+
+static void
+initialize_sve_state ()
+{
+  __asm __volatile ("dup z0.b, -1");
+  __asm __volatile ("dup z1.b, -1");
+  __asm __volatile ("dup z2.b, -1");
+  __asm __volatile ("dup z3.b, -1");
+  __asm __volatile ("dup z4.b, -1");
+  __asm __volatile ("dup z5.b, -1");
+  __asm __volatile ("dup z6.b, -1");
+  __asm __volatile ("dup z7.b, -1");
+  __asm __volatile ("dup z8.b, -1");
+  __asm __volatile ("dup z9.b, -1");
+  __asm __volatile ("dup z10.b, -1");
+  __asm __volatile ("dup z11.b, -1");
+  __asm __volatile ("dup z12.b, -1");
+  __asm __volatile ("dup z13.b, -1");
+  __asm __volatile ("dup z14.b, -1");
+  __asm __volatile ("dup z15.b, -1");
+  __asm __volatile ("dup z16.b, -1");
+  __asm __volatile ("dup z17.b, -1");
+  __asm __volatile ("dup z18.b, -1");
+  __asm __volatile ("dup z19.b, -1");
+  __asm __volatile ("dup z20.b, -1");
+  __asm __volatile ("dup z21.b, -1");
+  __asm __volatile ("dup z22.b, -1");
+  __asm __volatile ("dup z23.b, -1");
+  __asm __volatile ("dup z24.b, -1");
+  __asm __volatile ("dup z25.b, -1");
+  __asm __volatile ("dup z26.b, -1");
+  __asm __volatile ("dup z27.b, -1");
+  __asm __volatile ("dup z28.b, -1");
+  __asm __volatile ("dup z29.b, -1");
+  __asm __volatile ("dup z30.b, -1");
+  __asm __volatile ("dup z31.b, -1");
+  __asm __volatile ("ptrue p0.b");
+  __asm __volatile ("ptrue p1.b");
+  __asm __volatile ("ptrue p2.b");
+  __asm __volatile ("ptrue p3.b");
+  __asm __volatile ("ptrue p4.b");
+  __asm __volatile ("ptrue p5.b");
+  __asm __volatile ("ptrue p6.b");
+  __asm __volatile ("ptrue p7.b");
+  __asm __volatile ("ptrue p8.b");
+  __asm __volatile ("ptrue p9.b");
+  __asm __volatile ("ptrue p10.b");
+  __asm __volatile ("ptrue p11.b");
+  __asm __volatile ("ptrue p12.b");
+  __asm __volatile ("ptrue p13.b");
+  __asm __volatile ("ptrue p14.b");
+  __asm __volatile ("ptrue p15.b");
+  __asm __volatile ("setffr");
+}
+
+static int get_vl_size ()
+{
+  int res = prctl (PR_SVE_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_GET_VL (%d)", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int get_svl_size ()
+{
+  int res = prctl (PR_SME_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_GET_VL (%d)\n", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int set_vl_size (int new_vl)
+{
+  int res = prctl (PR_SVE_SET_VL, new_vl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_SET_VL (%d)\n", res);
+      return -1;
+    }
+
+  res = get_vl_size ();
+  if (res != new_vl)
+    {
+      printf ("Unexpected VL value (%d)\n", res);
+      return -1;
+    }
+
+  return res;
+}
+
+static int set_svl_size (int new_svl)
+{
+  int res = prctl (PR_SME_SET_VL, new_svl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_SET_VL (%d)\n", res);
+      return -1;
+    }
+
+  res = get_svl_size ();
+  if (res != new_svl)
+    {
+      printf ("Unexpected SVL value (%d)\n", res);
+      return -1;
+    }
+
+  return res;
+}
+
+/* Enable register states based on STATE.
+
+   0 - FPSIMD
+   1 - SVE
+   2 - SSVE
+   3 - ZA
+   4 - ZA and SSVE.  */
+
+void enable_states (int state)
+{
+  disable_za ();
+  disable_sm ();
+  initialize_fpsimd_state ();
+
+  if (state == 1)
+    {
+      initialize_sve_state ();
+    }
+  else if (state == 2)
+    {
+      enable_sm ();
+      initialize_sve_state ();
+    }
+  else if (state == 3)
+    {
+      enable_za ();
+      initialize_za_state ();
+    }
+  else if (state == 4)
+    {
+      enable_za ();
+      enable_sm ();
+      initialize_sve_state ();
+      initialize_za_state ();
+    }
+
+  return;
+}
+
+static int
+test_id_to_state (int id)
+{
+  return id / 25;
+}
+
+static int
+test_id_to_vl (int id)
+{
+  return 16 << ((id / 5) % 5);
+}
+
+static int
+test_id_to_svl (int id)
+{
+  return 16 << (id % 5);
+}
+
+static void
+dummy ()
+{
+}
+
+int
+main (int argc, char **argv)
+{
+  if (argc > 2)
+    printf ("Incorrect number of arguments passed to test.\n");
+
+  if (getauxval (AT_HWCAP) & HWCAP_SVE && getauxval (AT_HWCAP2) & HWCAP2_SME)
+    {
+      long test_id = 0;
+
+      /* If we have a test id passed as argument, read it now.  */
+      if (argc == 2)
+       test_id = strtol (argv[1], NULL, 0);
+
+      dummy (); /* stop to initialize test_id */
+
+      int state = test_id_to_state (test_id);
+      int vl = test_id_to_vl (test_id);
+      int svl = test_id_to_svl (test_id);
+
+      if (set_vl_size (vl) == -1 || set_svl_size (svl) == -1)
+       return -1;
+
+      enable_states (state);
+
+      /* Also set the TPIDR2 register so we can test dumping its contents
+        to a core file.  */
+      initialize_tpidr2 ();
+
+      char *p = 0x0;
+      *p = 0xff; /* crash point */
+    }
+  else
+    {
+      printf ("SKIP: no HWCAP_SVE or HWCAP2_SME on this system\n");
+      return -1;
+    }
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-core.exp.tcl b/gdb/testsuite/gdb.arch/aarch64-sme-core.exp.tcl
new file mode 100644 (file)
index 0000000..02d8c13
--- /dev/null
@@ -0,0 +1,184 @@
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Exercise core file reading/writing in the presence of SME support.
+# This test exercises GDB's dumping/loading capability for Linux
+# Kernel core files and for gcore core files.
+
+load_lib aarch64-scalable.exp
+
+#
+# Validate that CORE_FILENAME can be read correctly and that the register
+# state is sane.
+#
+proc check_sme_core_file { core_filename state vl svl } {
+    # Load the core file.
+    if [gdb_test "core $core_filename" \
+       [multi_line \
+           "Core was generated by.*\." \
+           "Program terminated with signal SIGSEGV, Segmentation fault\." \
+           "#0  ${::hex} in main \\(.*\\) at .*" \
+           ".*p = 0xff;.* crash point .*"] \
+           "load core file"] {
+       untested "failed to generate core file"
+       return -1
+    }
+
+    check_state $state $vl $svl
+
+    # Check the value of TPIDR2 in the core file.
+    gdb_test "print/x \$tpidr2" " = 0xffffffffffffffff" \
+            "tpidr2 contents from core file"
+}
+
+#
+# Generate two core files for EXECUTABLE, BINFILE with a test id of ID.
+# STATE is the register state, VL is the SVE vector length and SVL is the
+# SME vector length.
+# One of the core files is generated by the kernel and the other by the
+# gcore command.
+#
+proc generate_sme_core_files { executable binfile id state vl svl} {
+    # Run the program until the point where we need to adjust the
+    # test id.
+    set init_breakpoint "stop to initialize test_id"
+    gdb_breakpoint [gdb_get_line_number $init_breakpoint]
+    gdb_continue_to_breakpoint $init_breakpoint
+    gdb_test_no_output "set test_id = $id"
+
+    # Run the program until just before the crash.
+    set crash_breakpoint "crash point"
+    gdb_breakpoint [gdb_get_line_number $crash_breakpoint]
+    gdb_continue_to_breakpoint $crash_breakpoint
+    gdb_test_no_output "set print repeats 1" "adjust repeat count pre-crash"
+
+    # Adjust the register to custom values that we will check later when
+    # loading the core files.
+    check_state $state $vl $svl
+
+    # Continue until a crash.
+    gdb_test "continue" \
+       [multi_line \
+           "Program received signal SIGSEGV, Segmentation fault\." \
+           "${::hex} in main \\(.*\\) at .*" \
+           ".*p = 0xff;.* crash point .*"] \
+           "run to crash"
+
+    # Generate the gcore core file.
+    set gcore_filename [standard_output_file "${executable}-${id}-${state}-${vl}-${svl}.gcore"]
+    set gcore_generated [gdb_gcore_cmd "$gcore_filename" "generate gcore file"]
+
+    # Generate a native core file.
+    set core_filename [core_find ${binfile} {} $id]
+    set core_generated [expr {$core_filename != ""}]
+    set native_core_name "${binfile}-${id}-${state}-${vl}-${svl}.core"
+    remote_exec build "mv $core_filename ${native_core_name}"
+    set core_filename ${native_core_name}
+
+    # At this point we have a couple core files, the gcore one generated by GDB
+    # and the native one generated by the Linux Kernel.  Make sure GDB can read
+    # both correctly.
+    if {$gcore_generated} {
+       clean_restart ${binfile}
+       gdb_test_no_output "set print repeats 1" \
+           "adjust repeat count post-crash gcore"
+
+       with_test_prefix "gcore corefile" {
+           check_sme_core_file $gcore_filename $state $vl $svl
+       }
+    } else {
+       fail "gcore corefile not generated"
+    }
+
+    if {$core_generated} {
+       clean_restart ${binfile}
+
+       gdb_test_no_output "set print repeats 1" \
+           "adjust repeat count post-crash native core"
+
+       with_test_prefix "native corefile" {
+           check_sme_core_file $core_filename $state $vl $svl
+       }
+    } else {
+       untested "native corefile not generated"
+    }
+}
+
+#
+# Exercise core file reading (kernel-generated core files) and writing
+# (gcore command) for test id's ID_START through ID_END.
+#
+proc test_sme_core_file { id_start id_end } {
+    set compile_flags {"debug" "macros" "additional_flags=-march=armv8.5-a+sve"}
+    standard_testfile ${::srcdir}/${::subdir}/aarch64-sme-core.c
+    set executable "${::testfile}"
+    if {[prepare_for_testing "failed to prepare" ${executable} ${::srcfile} ${compile_flags}]} {
+       return -1
+    }
+    set binfile [standard_output_file ${executable}]
+
+    for {set id $id_start} {$id <= $id_end} {incr id} {
+       set state [test_id_to_state $id]
+       set vl [test_id_to_vl $id]
+       set svl [test_id_to_svl $id]
+
+       set skip_unsupported 0
+       if {![aarch64_supports_sve_vl $vl]
+           || ![aarch64_supports_sme_svl $svl]} {
+           # We have a vector length or streaming vector length that
+           # is not supported by this target.  Skip to the next iteration
+           # since it is no use running tests for an unsupported vector
+           # length.
+           if {![aarch64_supports_sve_vl $vl]} {
+               verbose -log "SVE vector length $vl not supported."
+           } elseif {![aarch64_supports_sme_svl $svl]} {
+               verbose -log "SME streaming vector length $svl not supported."
+           }
+           verbose -log "Skipping test."
+           set skip_unsupported 1
+       }
+
+       with_test_prefix "state=${state} vl=${vl} svl=${svl}" {
+           # If the SVE or SME vector length is not supported, just skip
+           # these next tests.
+           if {$skip_unsupported} {
+               untested "unsupported configuration on target"
+               continue
+           }
+
+           if ![runto_main] {
+               untested "could not run to main"
+               return -1
+           }
+
+           # Check if we are talking to a remote target.  If so, bail out,
+           # as right now remote targets can't communicate vector length (vl
+           # or svl) changes to gdb via the RSP.  When this restriction is
+           # lifted, we can remove this guard.
+           if {[gdb_is_target_remote]} {
+               unsupported "aarch64 sve/sme tests not supported for remote targets"
+               return -1
+           }
+
+           generate_sme_core_files ${executable} ${binfile} $id $state $vl $svl
+       }
+    }
+}
+
+require is_aarch64_target
+require allow_aarch64_sve_tests
+require allow_aarch64_sme_tests
+
+test_sme_core_file $id_start $id_end
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-0.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-0.exp
new file mode 100644 (file)
index 0000000..2a49801
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 16
+# SVL: 16, 32, 64, 128
+# This set covers 4 (0 ~ 3) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 0
+set id_end 3
+source $srcdir/$subdir/aarch64-sme-regs-available.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-1.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-1.exp
new file mode 100644 (file)
index 0000000..a58e89c
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 16
+# SVL: 256
+# This set covers 1 (4) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 4
+set id_end 4
+source $srcdir/$subdir/aarch64-sme-regs-available.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-2.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-2.exp
new file mode 100644 (file)
index 0000000..8b78e9e
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 32
+# SVL: 16, 32, 64, 128
+# This set covers 4 (5 ~ 8) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 5
+set id_end 8
+source $srcdir/$subdir/aarch64-sme-regs-available.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-3.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-3.exp
new file mode 100644 (file)
index 0000000..5794175
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 32
+# SVL: 256
+# This set covers 1 (9) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 9
+set id_end 9
+source $srcdir/$subdir/aarch64-sme-regs-available.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-4.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-4.exp
new file mode 100644 (file)
index 0000000..5d5e800
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 64
+# SVL: 16, 32, 64, 128
+# This set covers 4 (10 ~ 13) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 10
+set id_end 13
+source $srcdir/$subdir/aarch64-sme-regs-available.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-5.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-5.exp
new file mode 100644 (file)
index 0000000..42410d4
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 64
+# SVL: 256
+# This set covers 1 (14) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 14
+set id_end 14
+source $srcdir/$subdir/aarch64-sme-regs-available.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-6.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-6.exp
new file mode 100644 (file)
index 0000000..36692ac
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 128
+# SVL: 16, 32, 64, 128
+# This set covers 4 (15 ~ 18) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 15
+set id_end 18
+source $srcdir/$subdir/aarch64-sme-regs-available.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-7.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-7.exp
new file mode 100644 (file)
index 0000000..a3149e7
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 128
+# SVL: 256
+# This set covers 1 (19) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 19
+set id_end 19
+source $srcdir/$subdir/aarch64-sme-regs-available.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-8.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-8.exp
new file mode 100644 (file)
index 0000000..1859eaf
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 256
+# SVL: 16, 32, 64, 128
+# This set covers 4 (20 ~ 23) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 20
+set id_end 23
+source $srcdir/$subdir/aarch64-sme-regs-available.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-9.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-9.exp
new file mode 100644 (file)
index 0000000..cb30fc6
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 256
+# SVL: 256
+# This set covers 1 (24) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 24
+set id_end 24
+source $srcdir/$subdir/aarch64-sme-regs-available.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available.c b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available.c
new file mode 100644 (file)
index 0000000..58c01d0
--- /dev/null
@@ -0,0 +1,178 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2023 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Exercise various cases of reading/writing ZA contents for AArch64's
+   Scalable Matrix Extension.  */
+
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HWCAP_SVE
+#define HWCAP_SVE (1 << 22)
+#endif
+
+#ifndef HWCAP2_SME
+#define HWCAP2_SME (1 << 23)
+#endif
+
+#ifndef PR_SVE_SET_VL
+#define PR_SVE_SET_VL 50
+#define PR_SVE_GET_VL 51
+#define PR_SVE_VL_LEN_MASK 0xffff
+#endif
+
+#ifndef PR_SME_SET_VL
+#define PR_SME_SET_VL 63
+#define PR_SME_GET_VL 64
+#define PR_SME_VL_LEN_MASK 0xffff
+#endif
+
+static void
+enable_za ()
+{
+  /* smstart za */
+  __asm __volatile (".word 0xD503457F");
+}
+
+static void
+disable_za ()
+{
+  /* smstop za */
+  __asm __volatile (".word 0xD503447F");
+}
+
+static int get_vl_size ()
+{
+  int res = prctl (PR_SVE_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_GET_VL (%d)\n", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int get_svl_size ()
+{
+  int res = prctl (PR_SME_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_GET_VL (%d)\n", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int set_vl_size (int new_vl)
+{
+  int res = prctl (PR_SVE_SET_VL, new_vl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_SET_VL (%d)\n", res);
+      return -1;
+    }
+
+  res = get_vl_size ();
+  if (res != new_vl)
+    {
+      printf ("Unexpected VL value (%d)\n", res);
+      return -1;
+    }
+
+  return res;
+}
+
+static int set_svl_size (int new_svl)
+{
+  int res = prctl (PR_SME_SET_VL, new_svl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_SET_VL (%d)\n", res);
+      return -1;
+    }
+
+  res = get_svl_size ();
+  if (res != new_svl)
+    {
+      printf ("Unexpected SVL value (%d)\n", res);
+      return -1;
+    }
+
+  return res;
+}
+
+static int
+test_id_to_vl (int id)
+{
+  return 16 << ((id / 5) % 5);
+}
+
+static int
+test_id_to_svl (int id)
+{
+  return 16 << (id % 5);
+}
+
+static void
+dummy ()
+{
+}
+
+int
+main (int argc, char **argv)
+{
+  if (getauxval (AT_HWCAP) & HWCAP_SVE && getauxval (AT_HWCAP2) & HWCAP2_SME)
+    {
+      int id_start = ID_START;
+      int id_end = ID_END;
+
+      for (int id = id_start; id <= id_end; id++)
+       {
+         int vl = test_id_to_vl (id);
+         int svl = test_id_to_svl (id);
+
+         if (set_vl_size (vl) == -1 || set_svl_size (svl) == -1)
+           continue;
+
+         enable_za ();
+         dummy (); /* stop 1 */
+       }
+
+      for (int id = id_start; id <= id_end; id++)
+       {
+         int vl = test_id_to_vl (id);
+         int svl = test_id_to_svl (id);
+
+         if (set_vl_size (vl) == -1 || set_svl_size (svl) == -1)
+           continue;
+
+         disable_za ();
+         dummy (); /* stop 2 */
+       }
+    }
+  else
+    {
+      printf ("SKIP: no HWCAP_SVE or HWCAP2_SME on this system\n");
+      return -1;
+    }
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available.exp.tcl b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available.exp.tcl
new file mode 100644 (file)
index 0000000..a7b3640
--- /dev/null
@@ -0,0 +1,245 @@
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Exercise reading/writing ZA registers when there is ZA state.
+
+load_lib aarch64-scalable.exp
+
+#
+# Cycle through all ZA registers and pseudo-registers and validate that their
+# contents are available for vector length SVL.
+#
+# Make sure reading/writing to ZA registers work as expected.
+#
+proc check_regs { mode vl svl } {
+    # Check VG to make sure it is correct
+    set expected_vg [expr $vl / 8]
+    gdb_test "print \$vg" "= ${expected_vg}"
+
+    # Check SVG to make sure it is correct
+    set expected_svg [expr $svl / 8]
+    gdb_test "print \$svg" "= ${expected_svg}"
+
+    # If svl is adjusted by prctl, we will have ZA enabled.  If gdb is
+    # adjusting svl, ZA will not be enabled by default.  It will only be
+    # enabled when ZA is written to.
+    set za_state "= \\\[ ZA \\\]"
+    if {$mode == "gdb"} {
+       set za_state "= \\\[ \\\]"
+    }
+
+    # Check SVCR.
+    if [gdb_test "print \$svcr" $za_state "svcr before assignments" ] {
+       fail "incorrect za state"
+       return -1
+    }
+
+    # Check the size of ZA.
+    set expected_za_size [expr $svl * $svl]
+    gdb_test "print sizeof \$za" " = $expected_za_size"
+
+    # Check the size of Z0.
+    gdb_test "print sizeof \$z0" " = $vl"
+
+    # Exercise reading/writing from/to ZA.
+    initialize_2d_array "\$za" 255 $svl $svl
+    set pattern [string_to_regexp [2d_array_value_pattern 255 $svl $svl]]
+    gdb_test "print \$za" " = $pattern" "read back from za"
+
+    # Exercise reading/writing from/to the tile pseudo-registers.
+    set last_tile 1
+    set expected_size [expr $svl * $svl]
+    set tile_svl $svl
+    set za_state "= \\\[ ZA \\\]"
+    foreach_with_prefix granularity {"b" "h" "s" "d" "q"} {
+       for {set tile 0} {$tile < $last_tile} {incr tile} {
+           set register_name "\$za${tile}${granularity}"
+
+           # Test the size.
+           gdb_test "print sizeof ${register_name}" " = ${expected_size}"
+
+           # Test reading/writing
+           initialize_2d_array $register_name 255 $tile_svl $tile_svl
+
+           # Make sure we have ZA state.
+           if [gdb_test "print \$svcr" $za_state "svcr after assignment to ${register_name}" ] {
+               fail "incorrect za state"
+               return -1
+           }
+
+           set pattern [string_to_regexp [2d_array_value_pattern 255 $tile_svl $tile_svl]]
+           gdb_test "print $register_name" " = $pattern" "read back from $register_name"
+       }
+       set last_tile [expr $last_tile * 2]
+       set expected_size [expr $expected_size / 2]
+       set tile_svl [expr $tile_svl / 2]
+    }
+
+    # Exercise reading/writing from/to the tile slice pseudo-registers.
+    set last_tile 1
+    set last_slice $svl
+    set expected_size $svl
+    set num_elements $svl
+    foreach_with_prefix granularity {"b" "h" "s" "d" "q"} {
+       for {set tile 0} {$tile < $last_tile} {incr tile} {
+           for {set slice 0} {$slice < $last_slice} {incr slice} {
+               foreach_with_prefix direction {"h" "v"} {
+                   set register_name "\$za${tile}${direction}${granularity}${slice}"
+
+                   # Test the size.
+                   gdb_test "print sizeof ${register_name}" " = ${expected_size}"
+
+                   # Test reading/writing
+                   initialize_1d_array $register_name 255 $num_elements
+
+                   # Make sure we have ZA state.
+                   if [gdb_test "print \$svcr" $za_state "svcr after assignment of ${register_name}" ] {
+                       fail "incorrect za state"
+                       return -1
+                   }
+
+                   set pattern [string_to_regexp [1d_array_value_pattern 255 $num_elements]]
+                   gdb_test "print $register_name" " = $pattern" "read back from $register_name"
+               }
+           }
+       }
+       set last_tile [expr $last_tile * 2]
+       set last_slice [expr ($last_slice / 2)]
+       set num_elements [expr $num_elements / 2]
+    }
+}
+
+#
+# Cycle through all ZA registers and pseudo-registers and validate their
+# contents.
+#
+proc test_sme_registers_available { id_start id_end } {
+
+    set compile_flags {"debug" "macros"}
+    lappend compile_flags "additional_flags=-DID_START=${id_start}"
+    lappend compile_flags "additional_flags=-DID_END=${id_end}"
+
+    standard_testfile ${::srcdir}/${::subdir}/aarch64-sme-regs-available.c
+    set executable "${::testfile}-${id_start}-${id_end}"
+    if {[prepare_for_testing "failed to prepare" ${executable} ${::srcfile} ${compile_flags}]} {
+       return -1
+    }
+    set binfile [standard_output_file ${executable}]
+
+    if ![runto_main] {
+       untested "could not run to main"
+       return -1
+    }
+
+    # Check if we are talking to a remote target.  If so, bail out, as right now
+    # remote targets can't communicate vector length (vl or svl) changes to gdb
+    # via the RSP.  When this restriction is lifted, we can remove this guard.
+    if {[gdb_is_target_remote]} {
+       unsupported "aarch64 sve/sme tests not supported for remote targets"
+       return -1
+    }
+
+    gdb_test_no_output "set print repeats 1"
+
+    set prctl_breakpoint "stop 1"
+    gdb_breakpoint [gdb_get_line_number $prctl_breakpoint]
+
+    for {set id $id_start} {$id <= $id_end} {incr id} {
+       set vl [test_id_to_vl $id]
+       set svl [test_id_to_svl $id]
+
+       set skip_unsupported 0
+       if {![aarch64_supports_sve_vl $vl]
+           || ![aarch64_supports_sme_svl $svl]} {
+           # We have a vector length or streaming vector length that
+           # is not supported by this target.  Skip to the next iteration
+           # since it is no use running tests for an unsupported vector
+           # length.
+           if {![aarch64_supports_sve_vl $vl]} {
+               verbose -log "SVE vector length $vl not supported."
+           } elseif {![aarch64_supports_sme_svl $svl]} {
+               verbose -log "SME streaming vector length $svl not supported."
+           }
+           verbose -log "Skipping test."
+           set skip_unsupported 1
+       }
+
+       set mode "prctl"
+       with_test_prefix "$mode, vl=${vl} svl=${svl}" {
+           # If the SVE or SME vector length is not supported, just skip
+           # these next tests.
+           if {$skip_unsupported} {
+               untested "unsupported configuration on target"
+               continue
+           }
+
+           # Run the program until it has adjusted svl.
+           gdb_continue_to_breakpoint $prctl_breakpoint
+           check_regs $mode $vl $svl
+       }
+    }
+
+    set non_prctl_breakpoint "stop 2"
+    gdb_breakpoint [gdb_get_line_number $non_prctl_breakpoint]
+
+    for {set id $id_start} {$id <= $id_end} {incr id} {
+       set vl [test_id_to_vl $id]
+       set svl [test_id_to_svl $id]
+
+       set skip_unsupported 0
+       if {![aarch64_supports_sve_vl $vl]
+           || ![aarch64_supports_sme_svl $svl]} {
+           # We have a vector length or streaming vector length that
+           # is not supported by this target.  Skip to the next iteration
+           # since it is no use running tests for an unsupported vector
+           # length.
+           if {![aarch64_supports_sve_vl $vl]} {
+               verbose -log "SVE vector length $vl not supported."
+           } elseif {![aarch64_supports_sme_svl $svl]} {
+               verbose -log "SME streaming vector length $svl not supported."
+           }
+           verbose -log "Skipping test."
+           set skip_unsupported 1
+       }
+
+       set mode "gdb"
+       with_test_prefix "$mode, vl=${vl} svl=${svl}" {
+           # If the SVE or SME vector length is not supported, just skip
+           # these next tests.
+           if {$skip_unsupported} {
+               untested "unsupported configuration on target"
+               continue
+           }
+
+           # Run the program until we stop at the point where gdb should
+           # adjust the SVE and SME vector lengths.
+           gdb_continue_to_breakpoint $non_prctl_breakpoint
+
+           # Adjust svl via gdb.
+           set vg_value [expr $vl / 8]
+           set svg_value [expr $svl / 8]
+           gdb_test_no_output "set \$vg = ${vg_value}"
+           gdb_test_no_output "set \$svg = ${svg_value}"
+
+           check_regs $mode $vl $svl
+       }
+    }
+}
+
+require is_aarch64_target
+require allow_aarch64_sve_tests
+require allow_aarch64_sme_tests
+
+test_sme_registers_available $id_start $id_end
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-0.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-0.exp
new file mode 100644 (file)
index 0000000..ce8a7a7
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# state: FPSIMD
+# VL: 16, 32, 64, 128, 256
+# SVL: 16, 32, 64, 128, 256
+# This set covers 25 (0 ~ 24) out of 125 tests.
+set id_start 0
+set id_end 24
+source $srcdir/$subdir/aarch64-sme-regs-sigframe.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-1.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-1.exp
new file mode 100644 (file)
index 0000000..092d4b2
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# state: SVE
+# VL: 16, 32, 64, 128, 256
+# SVL: 16, 32, 64, 128, 256
+# This set covers 25 (25 ~ 49) out of 125 tests.
+set id_start 25
+set id_end 49
+source $srcdir/$subdir/aarch64-sme-regs-sigframe.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-2.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-2.exp
new file mode 100644 (file)
index 0000000..803d297
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# state: SSVE
+# VL: 16, 32, 64, 128, 256
+# SVL: 16, 32, 64, 128, 256
+# This set covers 25 (50 ~ 74) out of 125 tests.
+set id_start 50
+set id_end 74
+source $srcdir/$subdir/aarch64-sme-regs-sigframe.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-3.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-3.exp
new file mode 100644 (file)
index 0000000..d130757
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# state: ZA only
+# VL: 16, 32, 64, 128, 256
+# SVL: 16, 32, 64, 128, 256
+# This set covers 25 (75 ~ 99) out of 125 tests.
+set id_start 75
+set id_end 99
+source $srcdir/$subdir/aarch64-sme-regs-sigframe.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-4.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-4.exp
new file mode 100644 (file)
index 0000000..2b84b5d
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# state: ZA + SSVE
+# VL: 16, 32, 64, 128, 256
+# SVL: 16, 32, 64, 128, 256
+# This set covers 25 (100 ~ 124) out of 125 tests.
+set id_start 100
+set id_end 124
+source $srcdir/$subdir/aarch64-sme-regs-sigframe.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.c b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.c
new file mode 100644 (file)
index 0000000..9bc3e9c
--- /dev/null
@@ -0,0 +1,366 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2023 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Exercise AArch64's Scalable Vector/Matrix Extension signal frame handling
+   for GDB.  */
+
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+
+#ifndef HWCAP_SVE
+#define HWCAP_SVE (1 << 22)
+#endif
+
+#ifndef HWCAP2_SME
+#define HWCAP2_SME (1 << 23)
+#endif
+
+#ifndef PR_SVE_SET_VL
+#define PR_SVE_SET_VL 50
+#define PR_SVE_GET_VL 51
+#define PR_SVE_VL_LEN_MASK 0xffff
+#endif
+
+#ifndef PR_SME_SET_VL
+#define PR_SME_SET_VL 63
+#define PR_SME_GET_VL 64
+#define PR_SME_VL_LEN_MASK 0xffff
+#endif
+
+static int count = 0;
+
+static void
+handler (int sig)
+{
+  count++; /* handler */
+}
+
+static void
+enable_za ()
+{
+  /* smstart za */
+  __asm __volatile (".word 0xD503457F");
+}
+
+static void
+disable_za ()
+{
+  /* smstop za */
+  __asm __volatile (".word 0xD503447F");
+}
+
+static void
+enable_sm ()
+{
+  /* smstart sm */
+  __asm __volatile (".word 0xD503437F");
+}
+
+static void
+disable_sm ()
+{
+  /* smstop sm */
+  __asm __volatile (".word 0xD503427F");
+}
+
+static void
+initialize_fpsimd_state ()
+{
+  char buffer[16];
+
+  for (int i = 0; i < 16; i++)
+    buffer[i] = 0x55;
+
+  __asm __volatile ("mov x0, %0\n\t" \
+                   : : "r" (buffer));
+
+  __asm __volatile ("ldr q0, [x0]");
+  __asm __volatile ("ldr q1, [x0]");
+  __asm __volatile ("ldr q2, [x0]");
+  __asm __volatile ("ldr q3, [x0]");
+  __asm __volatile ("ldr q4, [x0]");
+  __asm __volatile ("ldr q5, [x0]");
+  __asm __volatile ("ldr q6, [x0]");
+  __asm __volatile ("ldr q7, [x0]");
+  __asm __volatile ("ldr q8, [x0]");
+  __asm __volatile ("ldr q9, [x0]");
+  __asm __volatile ("ldr q10, [x0]");
+  __asm __volatile ("ldr q11, [x0]");
+  __asm __volatile ("ldr q12, [x0]");
+  __asm __volatile ("ldr q13, [x0]");
+  __asm __volatile ("ldr q14, [x0]");
+  __asm __volatile ("ldr q15, [x0]");
+  __asm __volatile ("ldr q16, [x0]");
+  __asm __volatile ("ldr q17, [x0]");
+  __asm __volatile ("ldr q18, [x0]");
+  __asm __volatile ("ldr q19, [x0]");
+  __asm __volatile ("ldr q20, [x0]");
+  __asm __volatile ("ldr q21, [x0]");
+  __asm __volatile ("ldr q22, [x0]");
+  __asm __volatile ("ldr q23, [x0]");
+  __asm __volatile ("ldr q24, [x0]");
+  __asm __volatile ("ldr q25, [x0]");
+  __asm __volatile ("ldr q26, [x0]");
+  __asm __volatile ("ldr q27, [x0]");
+  __asm __volatile ("ldr q28, [x0]");
+  __asm __volatile ("ldr q29, [x0]");
+  __asm __volatile ("ldr q30, [x0]");
+  __asm __volatile ("ldr q31, [x0]");
+}
+
+static void
+initialize_za_state ()
+{
+  /* zero za */
+  __asm __volatile (".word 0xC00800FF");
+
+  char buffer[256];
+
+  for (int i = 0; i < 256; i++)
+    buffer[i] = 0xaa;
+
+  __asm __volatile ("mov x0, %0\n\t" \
+                   : : "r" (buffer));
+
+  /* Initialize loop boundaries.  */
+  __asm __volatile ("mov w12, 0");
+  __asm __volatile ("mov w17, 256");
+
+  /* loop: ldr za[w12, 0], [x0] */
+  __asm __volatile ("loop: .word 0xe1000000");
+  __asm __volatile ("add w12, w12, 1");
+  __asm __volatile ("cmp w12, w17");
+  __asm __volatile ("bne loop");
+}
+
+static void
+initialize_sve_state ()
+{
+  __asm __volatile ("dup z0.b, -1");
+  __asm __volatile ("dup z1.b, -1");
+  __asm __volatile ("dup z2.b, -1");
+  __asm __volatile ("dup z3.b, -1");
+  __asm __volatile ("dup z4.b, -1");
+  __asm __volatile ("dup z5.b, -1");
+  __asm __volatile ("dup z6.b, -1");
+  __asm __volatile ("dup z7.b, -1");
+  __asm __volatile ("dup z8.b, -1");
+  __asm __volatile ("dup z9.b, -1");
+  __asm __volatile ("dup z10.b, -1");
+  __asm __volatile ("dup z11.b, -1");
+  __asm __volatile ("dup z12.b, -1");
+  __asm __volatile ("dup z13.b, -1");
+  __asm __volatile ("dup z14.b, -1");
+  __asm __volatile ("dup z15.b, -1");
+  __asm __volatile ("dup z16.b, -1");
+  __asm __volatile ("dup z17.b, -1");
+  __asm __volatile ("dup z18.b, -1");
+  __asm __volatile ("dup z19.b, -1");
+  __asm __volatile ("dup z20.b, -1");
+  __asm __volatile ("dup z21.b, -1");
+  __asm __volatile ("dup z22.b, -1");
+  __asm __volatile ("dup z23.b, -1");
+  __asm __volatile ("dup z24.b, -1");
+  __asm __volatile ("dup z25.b, -1");
+  __asm __volatile ("dup z26.b, -1");
+  __asm __volatile ("dup z27.b, -1");
+  __asm __volatile ("dup z28.b, -1");
+  __asm __volatile ("dup z29.b, -1");
+  __asm __volatile ("dup z30.b, -1");
+  __asm __volatile ("dup z31.b, -1");
+  __asm __volatile ("ptrue p0.b");
+  __asm __volatile ("ptrue p1.b");
+  __asm __volatile ("ptrue p2.b");
+  __asm __volatile ("ptrue p3.b");
+  __asm __volatile ("ptrue p4.b");
+  __asm __volatile ("ptrue p5.b");
+  __asm __volatile ("ptrue p6.b");
+  __asm __volatile ("ptrue p7.b");
+  __asm __volatile ("ptrue p8.b");
+  __asm __volatile ("ptrue p9.b");
+  __asm __volatile ("ptrue p10.b");
+  __asm __volatile ("ptrue p11.b");
+  __asm __volatile ("ptrue p12.b");
+  __asm __volatile ("ptrue p13.b");
+  __asm __volatile ("ptrue p14.b");
+  __asm __volatile ("ptrue p15.b");
+  __asm __volatile ("setffr");
+}
+
+static int get_vl_size ()
+{
+  int res = prctl (PR_SVE_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_GET_VL (%d)\n", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int get_svl_size ()
+{
+  int res = prctl (PR_SME_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_GET_VL (%d)\n", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int set_vl_size (int new_vl)
+{
+  int res = prctl (PR_SVE_SET_VL, new_vl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_SET_VL (%d)\n", res);
+      return -1;
+    }
+
+  res = get_vl_size ();
+  if (res != new_vl)
+    {
+      printf ("Unexpected VL value (%d)\n", res);
+      return -1;
+    }
+
+  return res;
+}
+
+static int set_svl_size (int new_svl)
+{
+  int res = prctl (PR_SME_SET_VL, new_svl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_SET_VL (%d)\n", res);
+      return -1;
+    }
+
+  res = get_svl_size ();
+  if (res != new_svl)
+    {
+      printf ("Unexpected SVL value (%d)\n", res);
+      return -1;
+    }
+
+  return res;
+}
+
+/* Enable register states based on STATE.
+
+   0 - FPSIMD
+   1 - SVE
+   2 - SSVE
+   3 - ZA
+   4 - ZA and SSVE.  */
+
+void enable_states (int state)
+{
+  disable_za ();
+  disable_sm ();
+  initialize_fpsimd_state ();
+
+  if (state == 1)
+    {
+      initialize_sve_state ();
+    }
+  else if (state == 2)
+    {
+      enable_sm ();
+      initialize_sve_state ();
+    }
+  else if (state == 3)
+    {
+      enable_za ();
+      initialize_za_state ();
+    }
+  else if (state == 4)
+    {
+      enable_za ();
+      enable_sm ();
+      initialize_sve_state ();
+      initialize_za_state ();
+    }
+
+  return;
+}
+
+static int
+test_id_to_state (int id)
+{
+  return (id / 25);
+}
+
+static int
+test_id_to_vl (int id)
+{
+  return 16 << ((id / 5) % 5);
+}
+
+static int
+test_id_to_svl (int id)
+{
+  return 16 << (id % 5);
+}
+
+static void
+dummy ()
+{
+}
+
+int
+main (int argc, char **argv)
+{
+  if (getauxval (AT_HWCAP) & HWCAP_SVE && getauxval (AT_HWCAP2) & HWCAP2_SME)
+    {
+      int id_start = ID_START;
+      int id_end = ID_END;
+#ifdef SIGILL
+      signal (SIGILL, handler);
+#endif
+
+      int signal_count = 0;
+      for (int id = id_start; id <= id_end; id++)
+       {
+         int state = test_id_to_state (id);
+         int vl = test_id_to_vl (id);
+         int svl = test_id_to_svl (id);
+
+         if (set_vl_size (vl) == -1 || set_svl_size (svl) == -1)
+           continue;
+
+         signal_count++;
+         enable_states (state);
+         dummy (); /* stop before SIGILL */
+         __asm __volatile (".word 0xDEADBEEF"); /* illegal instruction */
+         while (signal_count != count);
+       }
+    }
+  else
+    {
+      printf ("SKIP: no HWCAP_SVE or HWCAP2_SME on this system\n");
+      return -1;
+    }
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.exp.tcl b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.exp.tcl
new file mode 100644 (file)
index 0000000..62b9076
--- /dev/null
@@ -0,0 +1,179 @@
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Exercise restoring SME/TPIDR2 state from a signal frame.
+
+load_lib aarch64-scalable.exp
+
+#
+# Validate the state of registers in the signal frame for various states.
+#
+proc test_sme_registers_sigframe { id_start id_end } {
+
+    set compile_flags {"debug" "macros"}
+    lappend compile_flags "additional_flags=-march=armv8.5-a+sve"
+    lappend compile_flags "additional_flags=-DID_START=${id_start}"
+    lappend compile_flags "additional_flags=-DID_END=${id_end}"
+
+    standard_testfile ${::srcdir}/${::subdir}/aarch64-sme-regs-sigframe.c
+    set executable "${::testfile}-${id_start}-${id_end}"
+    if {[prepare_for_testing "failed to prepare" ${executable} ${::srcfile} ${compile_flags}]} {
+       return -1
+    }
+    set binfile [standard_output_file ${executable}]
+
+    if ![runto_main] {
+       untested "could not run to main"
+       return -1
+    }
+
+    # Check if we are talking to a remote target.  If so, bail out, as right now
+    # remote targets can't communicate vector length (vl or svl) changes to gdb
+    # via the RSP.  When this restriction is lifted, we can remove this guard.
+    if {[gdb_is_target_remote]} {
+       unsupported "aarch64 sve/sme tests not supported for remote targets"
+       return -1
+    }
+
+    set sigill_breakpoint "stop before SIGILL"
+    set handler_breakpoint "handler"
+    gdb_breakpoint [gdb_get_line_number $sigill_breakpoint]
+    gdb_breakpoint [gdb_get_line_number $handler_breakpoint]
+
+    for {set id $id_start} {$id <= $id_end} {incr id} {
+       set state [test_id_to_state $id]
+       set vl [test_id_to_vl $id]
+       set svl [test_id_to_svl $id]
+
+       set skip_unsupported 0
+       if {![aarch64_supports_sve_vl $vl]
+           || ![aarch64_supports_sme_svl $svl]} {
+           # We have a vector length or streaming vector length that
+           # is not supported by this target.  Skip to the next iteration
+           # since it is no use running tests for an unsupported vector
+           # length.
+           if {![aarch64_supports_sve_vl $vl]} {
+               verbose -log "SVE vector length $vl not supported."
+           } elseif {![aarch64_supports_sme_svl $svl]} {
+               verbose -log "SME streaming vector length $svl not supported."
+           }
+           verbose -log "Skipping test."
+           set skip_unsupported 1
+       }
+
+       with_test_prefix "state=${state} vl=${vl} svl=${svl}" {
+
+           # If the SVE or SME vector length is not supported, just skip
+           # these next tests.
+           if {$skip_unsupported} {
+               untested "unsupported configuration on target"
+               continue
+           }
+
+           # Run the program until it has adjusted the svl.
+           if [gdb_continue_to_breakpoint $sigill_breakpoint] {
+               return -1
+           }
+
+           # Check SVG to make sure it is correct
+           set expected_svg [expr $svl / 8]
+           gdb_test "print \$svg" "= ${expected_svg}"
+
+           # Check the size of ZA.
+           set expected_za_size [expr $svl * $svl]
+           gdb_test "print sizeof \$za" " = $expected_za_size"
+
+           # Check the value of SVCR.
+           gdb_test "print \$svcr" [get_svcr_value $state] "svcr before signal"
+
+           # Handle SME ZA initialization and state.
+           set byte 0
+           if { $state == "za" || $state == "za_ssve" } {
+               set byte 170
+           }
+
+           # Set the expected ZA pattern.
+           set za_pattern [string_to_regexp [2d_array_value_pattern $byte $svl $svl]]
+
+           # Handle SVE/SSVE initialization and state.
+           set sve_vl $svl
+           if { $state == "ssve" || $state == "za_ssve" } {
+               # SVE state comes from SSVE.
+               set sve_vl $svl
+           } else {
+               # SVE state comes from regular SVE.
+               set sve_vl $vl
+           }
+
+           # Initialize the SVE state.
+           set sve_pattern [string_to_regexp [sve_value_pattern $state $sve_vl 85 255]]
+           for {set row 0} {$row < 32} {incr row} {
+               set register_name "\$z${row}\.b\.u"
+               gdb_test "print sizeof $register_name" " = $sve_vl" "size of $register_name"
+               gdb_test "print $register_name" $sve_pattern "read back from $register_name"
+           }
+
+           # Print ZA to check its value.
+           gdb_test "print \$za" $za_pattern "read back from za"
+
+           # Test TPIDR2 restore from signal frame as well.
+           gdb_test_no_output "set \$tpidr2=0x0102030405060708"
+
+           # Run to the illegal instruction.
+           if [gdb_test "continue" "Continuing\.\r\n\r\nProgram received signal SIGILL, Illegal instruction\..*in main.*"] {
+               return
+           }
+
+           # Skip the illegal instruction.  The signal handler will be called after we continue.
+           gdb_test_no_output "set \$pc=\$pc+4"
+           # Continue to the signal handler.
+           if [gdb_continue_to_breakpoint $handler_breakpoint] {
+               return -1
+           }
+
+           # Modify TPIDR2 so it is different from its value past the signal
+           # frame.
+           gdb_test_no_output "set \$tpidr2 = 0x0"
+
+           # Select the frame that contains "main".
+           gdb_test "frame 2" "#2.* main \\\(.*\\\) at.*"
+
+           for {set row 0} {$row < 32} {incr row} {
+               set register_name "\$z${row}\.b\.u"
+               gdb_test "print sizeof $register_name" " = $sve_vl" "size of $register_name in the signal frame"
+               gdb_test "print $register_name" $sve_pattern "$register_name contents from signal frame"
+           }
+
+           # Check the size of ZA in the signal frame.
+           set expected_za_size [expr $svl * $svl]
+           gdb_test "print sizeof \$za" " = $expected_za_size" "size of za in signal frame"
+
+           # Check the value of SVCR in the signal frame.
+           gdb_test "print \$svcr" [get_svcr_value $state] "svcr from signal frame"
+
+           # Check the value of ZA in the signal frame.
+           gdb_test "print \$za" $za_pattern "za contents from signal frame"
+
+           # Check the value of TPIDR2 in the signal frame.
+           gdb_test "print/x \$tpidr2" " = 0x102030405060708" "tpidr2 contents from signal frame"
+       }
+    }
+}
+
+require is_aarch64_target
+require allow_aarch64_sve_tests
+require allow_aarch64_sme_tests
+
+test_sme_registers_sigframe $id_start $id_end
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-0.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-0.exp
new file mode 100644 (file)
index 0000000..835f289
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 16
+# SVL: 16, 32, 64, 128
+# This set covers 4 (0 ~ 3) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 0
+set id_end 3
+source $srcdir/$subdir/aarch64-sme-regs-unavailable.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-1.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-1.exp
new file mode 100644 (file)
index 0000000..73ec3f6
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 16
+# SVL: 256
+# This set covers 1 (4) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 4
+set id_end 4
+source $srcdir/$subdir/aarch64-sme-regs-unavailable.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-2.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-2.exp
new file mode 100644 (file)
index 0000000..4d223ef
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 32
+# SVL: 16, 32, 64, 128
+# This set covers 4 (5 ~ 8) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 5
+set id_end 8
+source $srcdir/$subdir/aarch64-sme-regs-unavailable.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-3.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-3.exp
new file mode 100644 (file)
index 0000000..3a26cd3
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 32
+# SVL: 256
+# This set covers 1 (9) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 9
+set id_end 9
+source $srcdir/$subdir/aarch64-sme-regs-unavailable.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-4.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-4.exp
new file mode 100644 (file)
index 0000000..c8e73b7
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 64
+# SVL: 16, 32, 64, 128
+# This set covers 4 (10 ~ 13) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 10
+set id_end 13
+source $srcdir/$subdir/aarch64-sme-regs-unavailable.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-5.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-5.exp
new file mode 100644 (file)
index 0000000..7b9f908
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 64
+# SVL: 256
+# This set covers 1 (14) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 14
+set id_end 14
+source $srcdir/$subdir/aarch64-sme-regs-unavailable.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-6.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-6.exp
new file mode 100644 (file)
index 0000000..7a3d52f
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 128
+# SVL: 16, 32, 64, 128
+# This set covers 4 (15 ~ 18) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 15
+set id_end 18
+source $srcdir/$subdir/aarch64-sme-regs-unavailable.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-7.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-7.exp
new file mode 100644 (file)
index 0000000..03cff0a
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 128
+# SVL: 256
+# This set covers 1 (19) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 19
+set id_end 19
+source $srcdir/$subdir/aarch64-sme-regs-unavailable.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-8.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-8.exp
new file mode 100644 (file)
index 0000000..2379f3e
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 256
+# SVL: 16, 32, 64, 128
+# This set covers 4 (20 ~ 23) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 20
+set id_end 23
+source $srcdir/$subdir/aarch64-sme-regs-unavailable.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-9.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-9.exp
new file mode 100644 (file)
index 0000000..623e75b
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Exercise tests with the following parameters:
+# VL: 256
+# SVL: 256
+# This set covers 1 (24) out of 25 tests.
+#
+# These tests are split this way for parallelization and for performance
+# reasons.
+#
+set id_start 24
+set id_end 24
+source $srcdir/$subdir/aarch64-sme-regs-unavailable.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.c b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.c
new file mode 100644 (file)
index 0000000..9c844c9
--- /dev/null
@@ -0,0 +1,152 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2023 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Exercise various cases of ZA contents not being available for AArch64's
+   Scalable Matrix Extension.  */
+
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifndef HWCAP_SVE
+#define HWCAP_SVE (1 << 22)
+#endif
+
+#ifndef HWCAP2_SME
+#define HWCAP2_SME (1 << 23)
+#endif
+
+#ifndef PR_SVE_SET_VL
+#define PR_SVE_SET_VL 50
+#define PR_SVE_GET_VL 51
+#define PR_SVE_VL_LEN_MASK 0xffff
+#endif
+
+#ifndef PR_SME_SET_VL
+#define PR_SME_SET_VL 63
+#define PR_SME_GET_VL 64
+#define PR_SME_VL_LEN_MASK 0xffff
+#endif
+
+static int get_vl_size ()
+{
+  int res = prctl (PR_SVE_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_GET_VL (%d)\n", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int get_svl_size ()
+{
+  int res = prctl (PR_SME_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_GET_VL (%d)\n", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int set_vl_size (int new_vl)
+{
+  int res = prctl (PR_SVE_SET_VL, new_vl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_SET_VL (%d)\n", res);
+      return -1;
+    }
+
+  res = get_vl_size ();
+  if (res != new_vl)
+    {
+      printf ("Unexpected VL value (%d)\n", res);
+      return -1;
+    }
+
+  return res;
+}
+
+static int set_svl_size (int new_svl)
+{
+  int res = prctl (PR_SME_SET_VL, new_svl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_SET_VL (%d)\n", res);
+      return -1;
+    }
+
+  res = get_svl_size ();
+  if (res != new_svl)
+    {
+      printf ("Unexpected SVL value (%d)\n", res);
+      return -1;
+    }
+
+  return res;
+}
+
+static int
+test_id_to_vl (int id)
+{
+  return 16 << ((id / 5) % 5);
+}
+
+static int
+test_id_to_svl (int id)
+{
+  return 16 << (id % 5);
+}
+
+static void
+dummy ()
+{
+}
+
+int
+main (int argc, char **argv)
+{
+  if (getauxval (AT_HWCAP) & HWCAP_SVE && getauxval (AT_HWCAP2) & HWCAP2_SME)
+    {
+      int id_start = ID_START;
+      int id_end = ID_END;
+
+      for (int id = id_start; id <= id_end; id++)
+       {
+         int vl = test_id_to_vl (id);
+         int svl = test_id_to_svl (id);
+
+         if (set_vl_size (vl) == -1 || set_svl_size (svl) == -1)
+           continue;
+
+         dummy (); /* stop 1 */
+       }
+
+      dummy (); /* stop 2 */
+    }
+  else
+    {
+      printf ("SKIP: no HWCAP_SVE or HWCAP2_SME on this system\n");
+      return -1;
+    }
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.exp.tcl b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.exp.tcl
new file mode 100644 (file)
index 0000000..faeec4c
--- /dev/null
@@ -0,0 +1,212 @@
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Exercise the following:
+# - Printing ZA registers when there is no ZA state.
+# - Setting values of ZA registers when there is no ZA state.
+# - Validating ZA state is activated when we write to ZA registers.
+
+load_lib aarch64-scalable.exp
+
+#
+# Validate that the ZA registers have the expected state.
+#
+proc_with_prefix check_regs { vl svl } {
+    # Check VG to make sure it is correct
+    set expected_vg [expr $vl / 8]
+    gdb_test "print \$vg" "= ${expected_vg}"
+
+    # Check SVG to make sure it is correct
+    set expected_svg [expr $svl / 8]
+    gdb_test "print \$svg" "= ${expected_svg}"
+
+    # Make sure there is no SM or ZA state.
+    if [gdb_test "print \$svcr" "= \\\[ \\\]"] {
+       fail "incorrect ZA state"
+       return -1
+    }
+
+    # Check the size of ZA.
+    set expected_za_size [expr $svl * $svl]
+    gdb_test "print sizeof \$za" " = $expected_za_size"
+
+    # Check the size of Z0.
+    gdb_test "print sizeof \$z0" " = $vl"
+
+    # Set the expected ZA pattern.
+    set za_pattern [string_to_regexp [2d_array_value_pattern 0 $svl $svl]]
+
+    # Check ZA.
+    gdb_test "print \$za" $za_pattern
+
+    # Exercise reading/writing the tile slice pseudo-registers.
+    set last_tile 1
+    set last_slice $svl
+    set elements $svl
+    set expected_size $svl
+    foreach_with_prefix granularity {"b" "h" "s" "d" "q"} {
+       set pattern [string_to_regexp [1d_array_value_pattern 0 $elements]]
+       for {set tile 0} {$tile < $last_tile} {incr tile} {
+           for {set slice 0} {$slice < $last_slice} {incr slice} {
+               foreach_with_prefix direction {"h" "v"} {
+                   set register_name "\$za${tile}${direction}${granularity}${slice}"
+                   # Test the size.
+                   gdb_test "print sizeof ${register_name}" " = ${expected_size}"
+                   gdb_test "print ${register_name}" $pattern
+               }
+           }
+       }
+       set last_tile [expr $last_tile * 2]
+       set last_slice [expr ($last_slice / 2)]
+       set elements [expr ($elements / 2)]
+    }
+
+    # Exercise reading/writing the tile pseudo-registers.
+    set last_tile 1
+    set elements $svl
+    set expected_size [expr $svl * $svl]
+    foreach_with_prefix granularity {"b" "h" "s" "d" "q"} {
+       set pattern [string_to_regexp [2d_array_value_pattern 0 $elements $elements]]
+       for {set tile 0} {$tile < $last_tile} {incr tile} {
+           set register_name "\$za${tile}${granularity}"
+           # Test the size.
+           gdb_test "print sizeof ${register_name}" " = ${expected_size}"
+           gdb_test "print ${register_name}" $pattern
+       }
+       set last_tile [expr $last_tile * 2]
+       set expected_size [expr $expected_size / 2]
+       set elements [expr ($elements / 2)]
+    }
+}
+
+#
+# Cycle through all ZA registers and pseudo-registers and validate that their
+# contents are unavailable (zeroed out) for vector length SVL.
+#
+proc test_sme_registers_unavailable { id_start id_end } {
+
+    set compile_flags {"debug" "macros"}
+    lappend compile_flags "additional_flags=-DID_START=${id_start}"
+    lappend compile_flags "additional_flags=-DID_END=${id_end}"
+
+    standard_testfile ${::srcdir}/${::subdir}/aarch64-sme-regs-unavailable.c
+    set executable "${::testfile}-${id_start}-${id_end}"
+    if {[prepare_for_testing "failed to prepare" ${executable} ${::srcfile} ${compile_flags}]} {
+       return -1
+    }
+    set binfile [standard_output_file ${executable}]
+
+    if ![runto_main] {
+       untested "could not run to main"
+       return -1
+    }
+
+    # Check if we are talking to a remote target.  If so, bail out, as right now
+    # remote targets can't communicate vector length (vl or svl) changes to gdb
+    # via the RSP.  When this restriction is lifted, we can remove this guard.
+    if {[gdb_is_target_remote]} {
+       unsupported "aarch64 sve/sme tests not supported for remote targets"
+       return -1
+    }
+
+    gdb_test_no_output "set print repeats 1"
+
+    set prctl_breakpoint "stop 1"
+    gdb_breakpoint [gdb_get_line_number $prctl_breakpoint]
+
+    for {set id $id_start} {$id <= $id_end} {incr id} {
+       set vl [test_id_to_vl $id]
+       set svl [test_id_to_svl $id]
+
+       set skip_unsupported 0
+       if {![aarch64_supports_sve_vl $vl]
+           || ![aarch64_supports_sme_svl $svl]} {
+           # We have a vector length or streaming vector length that
+           # is not supported by this target.  Skip to the next iteration
+           # since it is no use running tests for an unsupported vector
+           # length.
+           if {![aarch64_supports_sve_vl $vl]} {
+               verbose -log "SVE vector length $vl not supported."
+           } elseif {![aarch64_supports_sme_svl $svl]} {
+               verbose -log "SME streaming vector length $svl not supported."
+           }
+           verbose -log "Skipping test."
+           set skip_unsupported 1
+       }
+
+       with_test_prefix "prctl, vl=${vl} svl=${svl}" {
+           # If the SVE or SME vector length is not supported, just skip
+           # these next tests.
+           if {$skip_unsupported} {
+               untested "unsupported configuration on target"
+               continue
+           }
+
+           # Run the program until it has adjusted svl.
+           gdb_continue_to_breakpoint $prctl_breakpoint
+
+           check_regs $vl $svl
+       }
+    }
+
+    set non_prctl_breakpoint "stop 2"
+    gdb_breakpoint [gdb_get_line_number $non_prctl_breakpoint]
+    gdb_continue_to_breakpoint $non_prctl_breakpoint
+
+    for {set id $id_start} {$id <= $id_end} {incr id} {
+       set vl [test_id_to_vl $id]
+       set svl [test_id_to_svl $id]
+
+       set skip_unsupported 0
+       if {![aarch64_supports_sve_vl $vl]
+           || ![aarch64_supports_sme_svl $svl]} {
+           # We have a vector length or streaming vector length that
+           # is not supported by this target.  Skip to the next iteration
+           # since it is no use running tests for an unsupported vector
+           # length.
+           if {![aarch64_supports_sve_vl $vl]} {
+               verbose -log "SVE vector length $vl not supported."
+           } elseif {![aarch64_supports_sme_svl $svl]} {
+               verbose -log "SME streaming vector length $svl not supported."
+           }
+           verbose -log "Skipping test."
+           set skip_unsupported 1
+       }
+
+       with_test_prefix "gdb, vl=${vl} svl=${svl}" {
+
+           # If the SVE or SME vector length is not supported, just skip
+           # these next tests.
+           if {$skip_unsupported} {
+               untested "unsupported configuration on target"
+               continue
+           }
+
+           # Adjust vg and svg.
+           set vg_value [expr $vl / 8]
+           set svg_value [expr $svl / 8]
+           gdb_test_no_output "set \$vg = ${vg_value}"
+           gdb_test_no_output "set \$svg = ${svg_value}"
+
+           check_regs $vl $svl
+       }
+    }
+}
+
+require is_aarch64_target
+require allow_aarch64_sve_tests
+require allow_aarch64_sme_tests
+
+test_sme_registers_unavailable $id_start $id_end
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-sanity.c b/gdb/testsuite/gdb.arch/aarch64-sme-sanity.c
new file mode 100644 (file)
index 0000000..694de06
--- /dev/null
@@ -0,0 +1,249 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2023 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Sanity test to exercise AArch64's Scalable Vector/Matrix Extension basic
+   functionality.  It cycles through different combinations of state and
+   initializes different register sets.  */
+
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HWCAP_SVE
+#define HWCAP_SVE (1 << 22)
+#endif
+
+#ifndef HWCAP2_SME
+#define HWCAP2_SME (1 << 23)
+#endif
+
+static void
+enable_za ()
+{
+  /* smstart za */
+  __asm __volatile (".word 0xD503457F");
+}
+
+static void
+disable_za ()
+{
+  /* smstop za */
+  __asm __volatile (".word 0xD503447F");
+}
+
+static void
+enable_sm ()
+{
+  /* smstart sm */
+  __asm __volatile (".word 0xD503437F");
+}
+
+static void
+disable_sm ()
+{
+  /* smstop sm */
+  __asm __volatile (".word 0xD503427F");
+}
+
+static void
+initialize_fpsimd_state ()
+{
+  char buffer[16];
+
+  for (int i = 0; i < 16; i++)
+    buffer[i] = 0x55;
+
+  __asm __volatile ("mov x0, %0\n\t" \
+                   : : "r" (buffer));
+
+  __asm __volatile ("ldr q0, [x0]");
+  __asm __volatile ("ldr q1, [x0]");
+  __asm __volatile ("ldr q2, [x0]");
+  __asm __volatile ("ldr q3, [x0]");
+  __asm __volatile ("ldr q4, [x0]");
+  __asm __volatile ("ldr q5, [x0]");
+  __asm __volatile ("ldr q6, [x0]");
+  __asm __volatile ("ldr q7, [x0]");
+  __asm __volatile ("ldr q8, [x0]");
+  __asm __volatile ("ldr q9, [x0]");
+  __asm __volatile ("ldr q10, [x0]");
+  __asm __volatile ("ldr q11, [x0]");
+  __asm __volatile ("ldr q12, [x0]");
+  __asm __volatile ("ldr q13, [x0]");
+  __asm __volatile ("ldr q14, [x0]");
+  __asm __volatile ("ldr q15, [x0]");
+  __asm __volatile ("ldr q16, [x0]");
+  __asm __volatile ("ldr q17, [x0]");
+  __asm __volatile ("ldr q18, [x0]");
+  __asm __volatile ("ldr q19, [x0]");
+  __asm __volatile ("ldr q20, [x0]");
+  __asm __volatile ("ldr q21, [x0]");
+  __asm __volatile ("ldr q22, [x0]");
+  __asm __volatile ("ldr q23, [x0]");
+  __asm __volatile ("ldr q24, [x0]");
+  __asm __volatile ("ldr q25, [x0]");
+  __asm __volatile ("ldr q26, [x0]");
+  __asm __volatile ("ldr q27, [x0]");
+  __asm __volatile ("ldr q28, [x0]");
+  __asm __volatile ("ldr q29, [x0]");
+  __asm __volatile ("ldr q30, [x0]");
+  __asm __volatile ("ldr q31, [x0]");
+}
+
+static void
+initialize_za_state ()
+{
+  /* zero za */
+  __asm __volatile (".word 0xC00800FF");
+
+  char buffer[256];
+
+  for (int i = 0; i < 256; i++)
+    buffer[i] = 0xaa;
+
+  __asm __volatile ("mov x0, %0\n\t" \
+                   : : "r" (buffer));
+
+  /* Initialize loop boundaries.  */
+  __asm __volatile ("mov w12, 0");
+  __asm __volatile ("mov w17, 256");
+
+  /* loop: ldr za[w12, 0], [x0] */
+  __asm __volatile ("loop: .word 0xe1000000");
+  __asm __volatile ("add w12, w12, 1");
+  __asm __volatile ("cmp w12, w17");
+  __asm __volatile ("bne loop");
+}
+
+static void
+initialize_sve_state ()
+{
+  __asm __volatile ("dup z0.b, -1");
+  __asm __volatile ("dup z1.b, -1");
+  __asm __volatile ("dup z2.b, -1");
+  __asm __volatile ("dup z3.b, -1");
+  __asm __volatile ("dup z4.b, -1");
+  __asm __volatile ("dup z5.b, -1");
+  __asm __volatile ("dup z6.b, -1");
+  __asm __volatile ("dup z7.b, -1");
+  __asm __volatile ("dup z8.b, -1");
+  __asm __volatile ("dup z9.b, -1");
+  __asm __volatile ("dup z10.b, -1");
+  __asm __volatile ("dup z11.b, -1");
+  __asm __volatile ("dup z12.b, -1");
+  __asm __volatile ("dup z13.b, -1");
+  __asm __volatile ("dup z14.b, -1");
+  __asm __volatile ("dup z15.b, -1");
+  __asm __volatile ("dup z16.b, -1");
+  __asm __volatile ("dup z17.b, -1");
+  __asm __volatile ("dup z18.b, -1");
+  __asm __volatile ("dup z19.b, -1");
+  __asm __volatile ("dup z20.b, -1");
+  __asm __volatile ("dup z21.b, -1");
+  __asm __volatile ("dup z22.b, -1");
+  __asm __volatile ("dup z23.b, -1");
+  __asm __volatile ("dup z24.b, -1");
+  __asm __volatile ("dup z25.b, -1");
+  __asm __volatile ("dup z26.b, -1");
+  __asm __volatile ("dup z27.b, -1");
+  __asm __volatile ("dup z28.b, -1");
+  __asm __volatile ("dup z29.b, -1");
+  __asm __volatile ("dup z30.b, -1");
+  __asm __volatile ("dup z31.b, -1");
+  __asm __volatile ("ptrue p0.b");
+  __asm __volatile ("ptrue p1.b");
+  __asm __volatile ("ptrue p2.b");
+  __asm __volatile ("ptrue p3.b");
+  __asm __volatile ("ptrue p4.b");
+  __asm __volatile ("ptrue p5.b");
+  __asm __volatile ("ptrue p6.b");
+  __asm __volatile ("ptrue p7.b");
+  __asm __volatile ("ptrue p8.b");
+  __asm __volatile ("ptrue p9.b");
+  __asm __volatile ("ptrue p10.b");
+  __asm __volatile ("ptrue p11.b");
+  __asm __volatile ("ptrue p12.b");
+  __asm __volatile ("ptrue p13.b");
+  __asm __volatile ("ptrue p14.b");
+  __asm __volatile ("ptrue p15.b");
+  __asm __volatile ("setffr");
+}
+
+/* Enable register states based on STATE.
+
+   0 - FPSIMD
+   1 - SVE
+   2 - SSVE
+   3 - ZA
+   4 - ZA and SSVE.  */
+
+void enable_states (int state)
+{
+  disable_za ();
+  disable_sm ();
+  initialize_fpsimd_state ();
+
+  if (state == 1)
+    {
+      initialize_sve_state ();
+    }
+  else if (state == 2)
+    {
+      enable_sm ();
+      initialize_sve_state ();
+    }
+  else if (state == 3)
+    {
+      enable_za ();
+      initialize_za_state ();
+    }
+  else if (state == 4)
+    {
+      enable_za ();
+      enable_sm ();
+      initialize_sve_state ();
+      initialize_za_state ();
+    }
+
+  return;
+}
+
+void dummy ()
+{
+}
+
+int
+main (int argc, char **argv)
+{
+  if (getauxval (AT_HWCAP) & HWCAP_SVE && getauxval (AT_HWCAP2) & HWCAP2_SME)
+    {
+      for (int state = 0; state < 5; state++)
+       {
+         enable_states (state);
+         dummy (); /* stop here */
+       }
+    }
+  else
+    {
+      printf ("SKIP: no HWCAP_SVE or HWCAP2_SME on this system\n");
+      return -1;
+    }
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-sanity.exp b/gdb/testsuite/gdb.arch/aarch64-sme-sanity.exp
new file mode 100644 (file)
index 0000000..3369976
--- /dev/null
@@ -0,0 +1,72 @@
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Sanity check for AArch64 Scalable Vector/Matrix Extensions functionality.
+
+load_lib aarch64-scalable.exp
+
+#
+# Run a series of basic checks for SVE/SME states.
+#
+proc sanity_check { vl svl } {
+    # Run the program until the point where we start initializing the different
+    # register states.
+    set state_breakpoint "stop here"
+    gdb_breakpoint [gdb_get_line_number $state_breakpoint]
+
+    for {set id 0} {$id < 5} {incr id} {
+       set state [state_id_to_state_string $id]
+
+       with_test_prefix "state=${state} vl=${vl} svl=${svl}" {
+           gdb_continue_to_breakpoint $state_breakpoint
+           check_state $state $vl $svl
+       }
+    }
+}
+
+require is_aarch64_target
+require allow_aarch64_sve_tests
+require allow_aarch64_sme_tests
+
+set compile_flags {"debug" "macros" "additional_flags=-march=armv8.5-a+sve"}
+standard_testfile
+if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile} ${compile_flags}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    return -1
+}
+
+# Check if we are talking to a remote target.  If so, bail out, as right now
+# remote targets can't communicate vector length (vl or svl) changes to gdb
+# via the RSP.  When this restriction is lifted, we can remove this guard.
+if {[gdb_is_target_remote]} {
+    unsupported "aarch64 sve/sme tests not supported for remote targets"
+    return -1
+}
+
+# Adjust the repeat count for the test.
+gdb_test_no_output "set print repeats 1" "adjust repeat count"
+
+# Fetch both the vector length and the streaming vector length the target
+# system is using.  We do not force any vector lengths and do not change
+# it mid-execution.
+set vl [expr [get_valueof "" "\$vg" "0" "fetch value of vl"] * 8]
+set svl [expr [get_valueof "" "\$svg" "0" "fetch value of svl"] * 8]
+
+# Now we are at the point where we can start checking state and moving the
+# testcase forward.
+sanity_check $vl $svl
diff --git a/gdb/testsuite/lib/aarch64-scalable.exp b/gdb/testsuite/lib/aarch64-scalable.exp
new file mode 100644 (file)
index 0000000..1be6919
--- /dev/null
@@ -0,0 +1,237 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Support routines for aarch64 scalable extension tests
+
+# Load generic aarch64 test dependencies.
+load_lib aarch64.exp
+
+#
+# Return a regular expression that matches what gdb would print for a
+# SVE Z register of length VL in state STATE.  The Z register should be filled
+# with BYTE_SVE and the FPSIMD registers should be filled with BYTE_FPSIMD.
+#
+# The pattern is of the form
+#
+# {BYTE_FPSIMD <repeats 16 times>}
+#
+# or
+#
+# {BYTE_FPSIMD <repeats 16 times>, 0 <repeats ... times>}
+#
+# or
+#
+# {BYTE_SVE <repeats VL times>}
+#
+proc sve_value_pattern { state vl byte_fpsimd byte_sve } {
+    set brace_open "{"
+    set brace_close "}"
+
+    append data $brace_open
+    if { $state == "fpsimd" || $state == "za" } {
+       if { $vl > 16 } {
+           set sve_repeat_count [expr $vl - 16]
+           append data "$byte_fpsimd <repeats 16 times>, 0 <repeats $sve_repeat_count times>"
+       } else {
+           append data "$byte_fpsimd <repeats 16 times>"
+       }
+    } else {
+       append data "$byte_sve <repeats $vl times>"
+    }
+    append data $brace_close
+
+    verbose -log "sve_value_pattern pattern string is..."
+    verbose -log $data
+    return $data
+}
+
+#
+# Return the SVCR value based on STATE.
+# SVCR is only available when SME is available.
+#
+proc get_svcr_value { state } {
+    if { $state == "ssve" } {
+      return "= \\\[ SM \\\]"
+    } elseif { $state == "za" } {
+      return "= \\\[ ZA \\\]"
+    } elseif { $state == "za_ssve" } {
+      return "= \\\[ SM ZA \\\]"
+    }
+
+  return "= \\\[ \\\]"
+}
+
+#
+# Return the state string based on STATE
+#
+proc state_id_to_state_string { state } {
+  if {$state == 0} {
+    return "fpsimd"
+  } elseif {$state == 1} {
+    return "sve"
+  } elseif {$state == 2} {
+    return "ssve"
+  } elseif {$state == 3} {
+    return "za"
+  } elseif {$state == 4} {
+    return "za_ssve"
+  }
+}
+
+#
+# Given a test ID, return the string representing the register state.
+# The state is one of fpsimd, sve, ssve, za and za_ssve.
+#
+proc test_id_to_state { id } {
+  set state [expr $id / 25]
+
+  return [state_id_to_state_string $state]
+}
+
+#
+# Given a test ID, return the associated vector length.
+#
+proc test_id_to_vl { id } {
+  return [expr 16 << (($id / 5) % 5)]
+}
+
+#
+# Given a test ID, return the associated streaming vector length.
+#
+proc test_id_to_svl { id } {
+  return [expr 16 << ($id % 5)]
+}
+
+#
+# Validate the values of the SVE registers.
+#
+proc check_sve_regs { byte state vl svl } {
+
+    # If streaming mode is enabled, the vector length is the streaming
+    # vector length.
+    set z_pattern ""
+    set z_size 0
+    if {$state == "ssve" || $state == "za_ssve"} {
+       set z_pattern [string_to_regexp [1d_array_value_pattern $byte $svl]]
+       set z_size $svl
+    } else {
+       set z_size $vl
+
+       if {$state == "fpsimd" || $state == "za"} {
+           # If there is no SVE/SSVE state, the contents of the Z/P/FFR registers
+           # are zero.
+           if {$vl == 16} {
+               set z_pattern [string_to_regexp [1d_array_value_pattern $byte $vl]]
+           } else {
+               set z_repeats [expr $vl - 16]
+               set z_pattern [string_to_regexp "{$byte <repeats 16 times>, 0 <repeats $z_repeats times>}"]
+             }
+       } else {
+           set z_pattern [string_to_regexp [1d_array_value_pattern $byte $vl]]
+       }
+    }
+    set p_size [expr $z_size / 8]
+
+    # If there is no SVE/SSVE state, the contents of the Z/P/FFR registers
+    # are zero.
+    set p_byte $byte
+    if {$state == "fpsimd" || $state == "za"} {
+       set p_byte 0
+    }
+    set p_pattern [string_to_regexp [1d_array_value_pattern $p_byte $p_size]]
+
+    for {set number 0} {$number < 32} {incr number} {
+       set register_name "\$z${number}\.b\.u"
+       gdb_test "print sizeof $register_name" " = $z_size"
+       gdb_test "print $register_name" $z_pattern
+    }
+
+    for {set number 0} {$number < 16} {incr number} {
+       set register_name "\$p${number}"
+       gdb_test "print sizeof $register_name" " = $p_size"
+       gdb_test "print $register_name" $p_pattern
+    }
+
+    gdb_test "print \$ffr" $p_pattern
+}
+
+#
+# Validate the values of the SME registers.
+#
+proc check_sme_regs { byte state svl } {
+    # ZA contents are only available when the ZA state is enabled.  Otherwise
+    # the ZA contents are unavailable (zeroed out).
+    set za_pattern ""
+    set expected_za_size [expr $svl * $svl]
+
+    if {$state != "za" && $state != "za_ssve"} {
+       set byte 0
+    }
+
+    set za_pattern [string_to_regexp [2d_array_value_pattern $byte $svl $svl]]
+
+    gdb_test "print sizeof \$za" " = $expected_za_size"
+    gdb_test "print \$za" $za_pattern
+}
+
+#
+# With register STATE, vector length VL and streaming vector length SVL,
+# run some register state checks to make sure the values are the expected
+# ones
+#
+proc check_state { state vl svl } {
+    # The FPSIMD registers are initialized with a value of 0x55 (85)
+    # for each byte.
+    #
+    # The SVE registers are initialized with a value of 0xff (255) for each
+    # byte, including the predicate registers and FFR.
+    #
+    # The SME (ZA) register is initialized with a value of 0xaa (170) for
+    # each byte.
+
+    # Check VG to make sure it is correct
+    set expected_vg [expr $vl / 8]
+    # If streaming mode is enabled, then vg is actually svg.
+    if {$state == "ssve" || $state == "za_ssve"} {
+       set expected_vg [expr $svl / 8]
+    }
+    gdb_test "print \$vg" " = ${expected_vg}"
+
+    # Check SVG to make sure it is correct
+    set expected_svg [expr $svl / 8]
+    gdb_test "print \$svg" " = ${expected_svg}"
+
+    # Check the value of SVCR.
+    gdb_test "print \$svcr" [get_svcr_value $state]
+
+    # When we have any SVE or SSVE state, the FPSIMD registers will have
+    # the same values as the SVE/SSVE Z registers.
+    set fpsimd_byte 85
+    if {$state == "sve" || $state == "ssve" || $state == "za_ssve"} {
+       set fpsimd_byte 255
+    }
+
+    set sve_byte 255
+    if {$state == "fpsimd" || $state == "za"} {
+       set sve_byte 85
+    }
+
+    # Check FPSIMD registers
+    check_fpsimd_regs $fpsimd_byte $state $vl $svl
+    # Check SVE registers
+    check_sve_regs $sve_byte $state $vl $svl
+    # Check SME registers
+    check_sme_regs 170 $state $svl
+}
diff --git a/gdb/testsuite/lib/aarch64-test-sme.c b/gdb/testsuite/lib/aarch64-test-sme.c
new file mode 100644 (file)
index 0000000..c123f37
--- /dev/null
@@ -0,0 +1,90 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2023 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* AArch64 SME feature check.  This test serves as a way for the GDB testsuite
+   to verify that a target supports SVE at runtime, and also reports data
+   about the various supported SME streaming vector lengths.  */
+
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HWCAP2_SME
+#define HWCAP2_SME (1 << 23)
+#endif
+
+#ifndef PR_SME_SET_VL
+#define PR_SME_SET_VL 63
+#define PR_SME_GET_VL 64
+#define PR_SME_VL_LEN_MASK 0xffff
+#endif
+
+static int get_svl_size ()
+{
+  int res = prctl (PR_SME_GET_VL, 0, 0, 0, 0);
+
+  if (res < 0)
+    return -1;
+
+  return (res & PR_SME_VL_LEN_MASK);
+}
+
+static int set_svl_size (int new_svl)
+{
+  if (prctl (PR_SME_SET_VL, new_svl, 0, 0, 0, 0) < 0)
+    return -1;
+
+  if (get_svl_size () != new_svl)
+    return -1;
+
+  return 0;
+}
+
+static void
+dummy ()
+{
+}
+
+#define SVL_MIN 16
+#define SVL_MAX 256
+#define SVL_INCREMENT_POWER 1
+
+int
+main (int argc, char **argv)
+{
+  /* Number of supported SME streaming vector lengths.  */
+  size_t supported_svl_count = 0;
+  /* Vector containing the various supported SME streaming vector lengths.  */
+  size_t supported_svl[5];
+
+  if (getauxval (AT_HWCAP) & HWCAP2_SME)
+    {
+      for (int svl = SVL_MIN; svl <= SVL_MAX; svl <<= SVL_INCREMENT_POWER)
+       {
+         if (set_svl_size (svl) == 0)
+           {
+             supported_svl[supported_svl_count] = svl;
+             supported_svl_count++;
+           }
+       }
+    }
+
+  return 0; /* stop here */
+}
diff --git a/gdb/testsuite/lib/aarch64-test-sve.c b/gdb/testsuite/lib/aarch64-test-sve.c
new file mode 100644 (file)
index 0000000..4673581
--- /dev/null
@@ -0,0 +1,90 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2023 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* AArch64 SVE feature check.  This test serves as a way for the GDB testsuite
+   to verify that a target supports SVE at runtime, and also reports data
+   about the various supported SVE vector lengths.  */
+
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HWCAP_SVE
+#define HWCAP_SVE (1 << 22)
+#endif
+
+#ifndef PR_SVE_SET_VL
+#define PR_SVE_SET_VL 50
+#define PR_SVE_GET_VL 51
+#define PR_SVE_VL_LEN_MASK 0xffff
+#endif
+
+static int get_vl_size ()
+{
+  int res = prctl (PR_SVE_GET_VL, 0, 0, 0, 0);
+
+  if (res < 0)
+    return -1;
+
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int set_vl_size (int new_vl)
+{
+  if (prctl (PR_SVE_SET_VL, new_vl, 0, 0, 0, 0) < 0)
+    return -1;
+
+  if (get_vl_size () != new_vl)
+    return -1;
+
+  return 0;
+}
+
+static void
+dummy ()
+{
+}
+
+#define VL_MIN 16
+#define VL_MAX 256
+#define VL_INCREMENT 16
+
+int
+main (int argc, char **argv)
+{
+  /* Number of supported SVE vector lengths.  */
+  size_t supported_vl_count = 0;
+  /* Vector containing the various supported SVE vector lengths.  */
+  size_t supported_vl[16];
+
+  if (getauxval (AT_HWCAP) & HWCAP_SVE)
+    {
+      for (int vl = VL_MIN; vl <= VL_MAX; vl += VL_INCREMENT)
+       {
+         if (set_vl_size (vl) == 0)
+           {
+             supported_vl[supported_vl_count] = vl;
+             supported_vl_count++;
+           }
+       }
+    }
+
+  return 0; /* stop here */
+}
diff --git a/gdb/testsuite/lib/aarch64.exp b/gdb/testsuite/lib/aarch64.exp
new file mode 100644 (file)
index 0000000..cd43a4c
--- /dev/null
@@ -0,0 +1,153 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Support routines for aarch64-specific tests
+
+#
+# Return a regular expression that matches what gdb would print for a
+# 1-dimension vector containing ELEMENTS elements of value BYTE.
+#
+# The pattern is of the form "{BYTE <repeats ELEMENTS times>".
+#
+proc 1d_array_value_pattern { byte elements } {
+    set brace_open "{"
+    set brace_close "}"
+
+    append data $brace_open $byte
+    if {$elements > 1} {
+       append data " <repeats $elements times>"
+    }
+    append data $brace_close
+
+    verbose -log "1d_array_value_pattern Pattern string is..."
+    verbose -log $data
+    return $data
+}
+
+#
+# Return a regular expression that matches what gdb would print for a
+# 2-dimension vector containing ROWS rows and COLUMNS columns of elements
+# of value BYTE.
+#
+# The pattern is of the form
+# "{{BYTE <repeats COLUMNS times>} <repeats ROWS times>}".
+#
+proc 2d_array_value_pattern { byte rows columns } {
+    set brace_open "{"
+    set brace_close "}"
+
+    append data $brace_open [1d_array_value_pattern $byte $columns]
+    if {$rows > 1} {
+       append data " <repeats $rows times>"
+    }
+    append data $brace_close
+
+    verbose -log "2d_array_value_pattern Pattern string is..."
+    verbose -log $data
+    return $data
+}
+
+#
+# Initialize register NAME, a 1-dimension vector, with ELEMENTS elements
+# by setting all elements to BYTE.  ELEMENTS is limited at 256 for memory
+# usage purposes.
+#
+# The initialization is of the form "{BYTE, BYTE, BYTE ...}".
+#
+proc initialize_1d_array { name byte elements } {
+    set brace_open "{"
+    set brace_close "}"
+
+    append data $brace_open
+
+    # Build the assignment in a single shot.
+    for {set element 0} {$element < $elements} {incr element} {
+       # Construct the initializer by appending elements to it.
+       append data $byte
+
+       # If this isn't the last element, add a comma.
+       if {[expr $element + 1] < $elements} {
+           append data ", "
+       }
+    }
+    append data $brace_close
+
+    verbose -log "initialization string is..."
+    verbose -log $data
+    gdb_test_no_output "set $name = $data" "write to $name"
+}
+
+#
+# Return an initializer string for a 2-dimension vector with ROWS rows and
+# COLUMNS columns, initializing all elements to BYTE for register NAME.
+#
+# COLUMNS is limited to 256 elements for memory usage purposes.
+#
+# The initialization is of the form "{{BYTE, BYTE}, ..., {BYTE, BYTE}}}".
+#
+proc initialize_2d_array { name byte rows columns } {
+    set brace_open "{"
+    set brace_close "}"
+
+    if {[expr $rows * $columns] <= 256} {
+       # Build the assignment in a single shot, as we have a maximum of 256
+       # elements.
+       for {set row 0} {$row < $rows} {incr row} {
+           append data $brace_open
+           for {set column 0} {$column < $columns} {incr column} {
+               # Construct the initializer by appending elements to it.
+               append data $byte
+
+               # If this isn't the last column, add a comma.
+               if {[expr $column + 1] < $columns} {
+                   append data ", "
+               }
+           }
+
+           append data $brace_close
+
+           # If this isn't the last row, add a comma.
+           if {[expr $row + 1] < $rows} {
+               append data ","
+           }
+       }
+
+       set data $brace_open$data
+       set data $data$brace_close
+
+       verbose -log "initialization string is..."
+       verbose -log $data
+       gdb_test_no_output "set $name = $data" "write to $name"
+    } else {
+       # There are too many elements to initialize (more than 256), so we
+       # will do the initialization row by row.
+       for {set row 0} {$row < $rows} {incr row} {
+           initialize_1d_array "$name\[$row\]" $byte $columns
+       }
+    }
+}
+
+#
+# Validate the values of the FPSIMD registers.
+#
+proc check_fpsimd_regs { byte state vl svl} {
+    set fpsimd_pattern [string_to_regexp [1d_array_value_pattern $byte 16]]
+
+    for {set number 0} {$number < 32} {incr number} {
+       set register_name "\$v${number}\.b\.u"
+       gdb_test "print sizeof $register_name" " = 16"
+       gdb_test "print $register_name" $fpsimd_pattern
+    }
+}
index de22da8d8a8c6bb7f5486a03e9c52ebe25b189ad..c9f1f666eb8ae013c02911f487a73e71e84a0bad 100644 (file)
@@ -4152,10 +4152,259 @@ gdb_caching_proc allow_aarch64_sve_tests {} {
     gdb_exit
     remote_file build delete $obj
 
+    # While testing for SVE support, also discover all the supported vector
+    # length values.
+    aarch64_initialize_sve_information
+
     verbose "$me:  returning $allow_sve_tests" 2
     return $allow_sve_tests
 }
 
+# Assuming SVE is supported by the target, run some checks to determine all
+# the supported vector length values and return an array containing all of those
+# values.  Since this is a gdb_caching_proc, this proc will only be executed
+# once.
+#
+# To check if a particular SVE vector length is supported, the following code
+# can be used. For instance, for vl == 16:
+#
+# if {[aarch64_supports_sve_vl 16]} {
+#     verbose -log "SVE vector length 16 is supported."
+# }
+#
+# This procedure should NEVER be called by hand, as it reinitializes the GDB
+# session and will derail a test.  This should be called automatically as part
+# of the SVE support test routine allow_aarch64_sve_tests.  Users should
+# restrict themselves to calling the helper proc aarch64_supports_sve_vl.
+
+gdb_caching_proc aarch64_initialize_sve_information { } {
+    global srcdir
+
+    set src "${srcdir}/lib/aarch64-test-sve.c"
+    set test_exec [standard_temp_file "aarch64-test-sve.x"]
+    set compile_flags "{additional_flags=-march=armv8-a+sve}"
+    array set supported_vl {}
+
+    # Compile the SVE vector length test.
+    set result [gdb_compile $src $test_exec executable [list debug ${compile_flags} nowarnings]]
+
+    if {$result != ""} {
+       verbose -log "Failed to compile SVE information gathering test."
+       return [array get supported_vl]
+    }
+
+    clean_restart $test_exec
+
+    if {![runto_main]} {
+       return [array get supported_vl]
+    }
+
+    set stop_breakpoint "stop here"
+    gdb_breakpoint [gdb_get_line_number $stop_breakpoint $src]
+    gdb_continue_to_breakpoint $stop_breakpoint
+
+    # Go through the data and extract the supported SVE vector lengths.
+    set vl_count [get_valueof "" "supported_vl_count" "0" \
+                             "fetch value of supported_vl_count"]
+    verbose -log "Found $vl_count supported SVE vector length values"
+
+    for {set vl_index 0} {$vl_index < $vl_count} {incr vl_index} {
+       set test_vl [get_valueof "" "supported_vl\[$vl_index\]" "0" \
+                                "fetch value of supported_vl\[$vl_index\]"]
+
+       # Mark this vector length as supported.
+       if {$test_vl != 0} {
+           verbose -log "Found supported SVE vector length $test_vl"
+           set supported_vl($test_vl) 1
+       }
+    }
+
+    gdb_exit
+    verbose -log "Cleaning up"
+    remote_file build delete $test_exec
+
+    verbose -log "Done gathering information about AArch64 SVE vector lengths."
+
+    # Return the array containing all of the supported SVE vl values.
+    return [array get supported_vl]
+}
+
+#
+# Return 1 if the target supports SVE vl LENGTH
+# Return 0 otherwise.
+#
+
+proc aarch64_supports_sve_vl { length } {
+
+    # Fetch the cached array of supported SVE vl values.
+    array set supported_vl [aarch64_initialize_sve_information]
+
+    # Do we have the global values cached?
+    if {![info exists supported_vl($length)]} {
+       verbose -log "Target does not support SVE vl $length"
+       return 0
+    }
+
+    # The target supports SVE vl LENGTH.
+    return 1
+}
+
+# Run a test on the target to see if it supports Aarch64 SME extensions.
+# Return 0 if so, 1 if it does not.  Note this causes a restart of GDB.
+
+gdb_caching_proc allow_aarch64_sme_tests {} {
+    global srcdir subdir gdb_prompt inferior_exited_re
+
+    set me "allow_aarch64_sme_tests"
+
+    if { ![is_aarch64_target]} {
+       return 0
+    }
+
+    set compile_flags "{additional_flags=-march=armv8-a+sme}"
+
+    # Compile a test program containing SME instructions.
+    set src {
+       int main() {
+           asm volatile ("smstart za");
+           return 0;
+       }
+    }
+    if {![gdb_simple_compile $me $src executable $compile_flags]} {
+       # Try again, but with a raw hex instruction so we don't rely on
+       # assembler support for SME.
+
+       set compile_flags "{additional_flags=-march=armv8-a}"
+
+       # Compile a test program containing SME instructions.
+       set src {
+           int main() {
+               asm volatile (".word 0xD503457F");
+               return 0;
+           }
+       }
+
+       if {![gdb_simple_compile $me $src executable $compile_flags]} {
+           return 0
+       }
+    }
+
+    # Compilation succeeded so now run it via gdb.
+    clean_restart $obj
+    gdb_run_cmd
+    gdb_expect {
+       -re ".*Illegal instruction.*${gdb_prompt} $" {
+           verbose -log "\n$me sme support not detected"
+           set allow_sme_tests 0
+       }
+       -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
+           verbose -log "\n$me: sme support detected"
+           set allow_sme_tests 1
+       }
+       default {
+         warning "\n$me: default case taken"
+           set allow_sme_tests 0
+       }
+    }
+    gdb_exit
+    remote_file build delete $obj
+
+    # While testing for SME support, also discover all the supported vector
+    # length values.
+    aarch64_initialize_sme_information
+
+    verbose "$me:  returning $allow_sme_tests" 2
+    return $allow_sme_tests
+}
+
+# Assuming SME is supported by the target, run some checks to determine all
+# the supported streaming vector length values and return an array containing
+# all of those values.  Since this is a gdb_caching_proc, this proc will only
+# be executed once.
+#
+# To check if a particular SME streaming vector length is supported, the
+# following code can be used. For instance, for svl == 32:
+#
+# if {[aarch64_supports_sme_svl 32]} {
+#     verbose -log "SME streaming vector length 32 is supported."
+# }
+#
+# This procedure should NEVER be called by hand, as it reinitializes the GDB
+# session and will derail a test.  This should be called automatically as part
+# of the SME support test routine allow_aarch64_sme_tests.  Users should
+# restrict themselves to calling the helper proc aarch64_supports_sme_svl.
+
+gdb_caching_proc aarch64_initialize_sme_information { } {
+    global srcdir
+
+    set src "${srcdir}/lib/aarch64-test-sme.c"
+    set test_exec [standard_temp_file "aarch64-test-sme.x"]
+    set compile_flags "{additional_flags=-march=armv8-a+sme}"
+    array set supported_svl {}
+
+    # Compile the SME vector length test.
+    set result [gdb_compile $src $test_exec executable [list debug ${compile_flags} nowarnings]]
+
+    if {$result != ""} {
+       verbose -log "Failed to compile SME information gathering test."
+       return [array get supported_svl]
+    }
+
+    clean_restart $test_exec
+
+    if {![runto_main]} {
+       return [array get supported_svl]
+    }
+
+    set stop_breakpoint "stop here"
+    gdb_breakpoint [gdb_get_line_number $stop_breakpoint $src]
+    gdb_continue_to_breakpoint $stop_breakpoint
+
+    # Go through the data and extract the supported SME vector lengths.
+    set svl_count [get_valueof "" "supported_svl_count" "0" \
+                              "fetch value of supported_svl_count"]
+    verbose -log "Found $svl_count supported SME vector length values"
+
+    for {set svl_index 0} {$svl_index < $svl_count} {incr svl_index} {
+       set test_svl [get_valueof "" "supported_svl\[$svl_index\]" "0" \
+                                 "fetch value of supported_svl\[$svl_index\]"]
+
+       # Mark this streaming vector length as supported.
+       if {$test_svl != 0} {
+           verbose -log "Found supported SME vector length $test_svl"
+           set supported_svl($test_svl) 1
+       }
+    }
+
+    gdb_exit
+    verbose -log "Cleaning up"
+    remote_file build delete $test_exec
+
+    verbose -log "Done gathering information about AArch64 SME vector lengths."
+
+    # Return the array containing all of the supported SME svl values.
+    return [array get supported_svl]
+}
+
+#
+# Return 1 if the target supports SME svl LENGTH
+# Return 0 otherwise.
+#
+
+proc aarch64_supports_sme_svl { length } {
+
+    # Fetch the cached array of supported SME svl values.
+    array set supported_svl [aarch64_initialize_sme_information]
+
+    # Do we have the global values cached?
+    if {![info exists supported_svl($length)]} {
+       verbose -log "Target does not support SME svl $length"
+       return 0
+    }
+
+    # The target supports SME svl LENGTH.
+    return 1
+}
 
 # A helper that compiles a test case to see if __int128 is supported.
 proc gdb_int128_helper {lang} {