From 16582a51c6e5ed05812d40050f63f35a2c7710c1 Mon Sep 17 00:00:00 2001 From: Luis Machado Date: Mon, 10 Oct 2022 13:31:44 +0100 Subject: [PATCH] sme: Add SVE/SME testcases 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 Reviewed-by: Thiago Jung Bauermann --- gdb/testsuite/gdb.arch/aarch64-sme-core-0.exp | 23 ++ gdb/testsuite/gdb.arch/aarch64-sme-core-1.exp | 23 ++ gdb/testsuite/gdb.arch/aarch64-sme-core-2.exp | 23 ++ gdb/testsuite/gdb.arch/aarch64-sme-core-3.exp | 23 ++ gdb/testsuite/gdb.arch/aarch64-sme-core-4.exp | 23 ++ gdb/testsuite/gdb.arch/aarch64-sme-core.c | 372 ++++++++++++++++++ .../gdb.arch/aarch64-sme-core.exp.tcl | 184 +++++++++ .../gdb.arch/aarch64-sme-regs-available-0.exp | 26 ++ .../gdb.arch/aarch64-sme-regs-available-1.exp | 26 ++ .../gdb.arch/aarch64-sme-regs-available-2.exp | 26 ++ .../gdb.arch/aarch64-sme-regs-available-3.exp | 26 ++ .../gdb.arch/aarch64-sme-regs-available-4.exp | 26 ++ .../gdb.arch/aarch64-sme-regs-available-5.exp | 26 ++ .../gdb.arch/aarch64-sme-regs-available-6.exp | 26 ++ .../gdb.arch/aarch64-sme-regs-available-7.exp | 26 ++ .../gdb.arch/aarch64-sme-regs-available-8.exp | 26 ++ .../gdb.arch/aarch64-sme-regs-available-9.exp | 26 ++ .../gdb.arch/aarch64-sme-regs-available.c | 178 +++++++++ .../aarch64-sme-regs-available.exp.tcl | 245 ++++++++++++ .../gdb.arch/aarch64-sme-regs-sigframe-0.exp | 23 ++ .../gdb.arch/aarch64-sme-regs-sigframe-1.exp | 23 ++ .../gdb.arch/aarch64-sme-regs-sigframe-2.exp | 23 ++ .../gdb.arch/aarch64-sme-regs-sigframe-3.exp | 23 ++ .../gdb.arch/aarch64-sme-regs-sigframe-4.exp | 23 ++ .../gdb.arch/aarch64-sme-regs-sigframe.c | 366 +++++++++++++++++ .../aarch64-sme-regs-sigframe.exp.tcl | 179 +++++++++ .../aarch64-sme-regs-unavailable-0.exp | 26 ++ .../aarch64-sme-regs-unavailable-1.exp | 26 ++ .../aarch64-sme-regs-unavailable-2.exp | 26 ++ .../aarch64-sme-regs-unavailable-3.exp | 26 ++ .../aarch64-sme-regs-unavailable-4.exp | 26 ++ .../aarch64-sme-regs-unavailable-5.exp | 26 ++ .../aarch64-sme-regs-unavailable-6.exp | 26 ++ .../aarch64-sme-regs-unavailable-7.exp | 26 ++ .../aarch64-sme-regs-unavailable-8.exp | 26 ++ .../aarch64-sme-regs-unavailable-9.exp | 26 ++ .../gdb.arch/aarch64-sme-regs-unavailable.c | 152 +++++++ .../aarch64-sme-regs-unavailable.exp.tcl | 212 ++++++++++ gdb/testsuite/gdb.arch/aarch64-sme-sanity.c | 249 ++++++++++++ gdb/testsuite/gdb.arch/aarch64-sme-sanity.exp | 72 ++++ gdb/testsuite/lib/aarch64-scalable.exp | 237 +++++++++++ gdb/testsuite/lib/aarch64-test-sme.c | 90 +++++ gdb/testsuite/lib/aarch64-test-sve.c | 90 +++++ gdb/testsuite/lib/aarch64.exp | 153 +++++++ gdb/testsuite/lib/gdb.exp | 249 ++++++++++++ 45 files changed, 3778 insertions(+) create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-core-0.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-core-1.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-core-2.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-core-3.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-core-4.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-core.c create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-core.exp.tcl create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available-0.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available-1.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available-2.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available-3.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available-4.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available-5.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available-6.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available-7.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available-8.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available-9.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available.c create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available.exp.tcl create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-0.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-1.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-2.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-3.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-4.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.c create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.exp.tcl create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-0.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-1.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-2.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-3.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-4.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-5.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-6.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-7.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-8.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-9.exp create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.c create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.exp.tcl create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-sanity.c create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-sanity.exp create mode 100644 gdb/testsuite/lib/aarch64-scalable.exp create mode 100644 gdb/testsuite/lib/aarch64-test-sme.c create mode 100644 gdb/testsuite/lib/aarch64-test-sve.c create mode 100644 gdb/testsuite/lib/aarch64.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 index 00000000000..5a51bbd8a1d --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-core-0.exp @@ -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 . */ + +# 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 index 00000000000..41e93b15834 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-core-1.exp @@ -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 . */ + +# 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 index 00000000000..05144d9f560 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-core-2.exp @@ -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 . */ + +# 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 index 00000000000..fa8931a46d1 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-core-3.exp @@ -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 . */ + +# 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 index 00000000000..8881898b370 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-core-4.exp @@ -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 . */ + +# 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 index 00000000000..d71d18ebd3b --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-core.c @@ -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 . */ + +/* 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 +#include +#include +#include +#include +#include + +#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 index 00000000000..02d8c13af81 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-core.exp.tcl @@ -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 . +# +# 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 index 00000000000..2a4980171e7 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-0.exp @@ -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 . */ + +# 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 index 00000000000..a58e89caab3 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-1.exp @@ -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 . */ + +# 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 index 00000000000..8b78e9ec639 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-2.exp @@ -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 . */ + +# 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 index 00000000000..57941758870 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-3.exp @@ -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 . */ + +# 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 index 00000000000..5d5e800d328 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-4.exp @@ -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 . */ + +# 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 index 00000000000..42410d4eb20 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-5.exp @@ -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 . */ + +# 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 index 00000000000..36692ac31c1 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-6.exp @@ -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 . */ + +# 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 index 00000000000..a3149e7fcae --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-7.exp @@ -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 . */ + +# 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 index 00000000000..1859eaf9960 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-8.exp @@ -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 . */ + +# 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 index 00000000000..cb30fc63724 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-9.exp @@ -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 . */ + +# 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 index 00000000000..58c01d0bf9a --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available.c @@ -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 . */ + +/* Exercise various cases of reading/writing ZA contents for AArch64's + Scalable Matrix Extension. */ + +#include +#include +#include +#include +#include +#include + +#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 index 00000000000..a7b36402dff --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available.exp.tcl @@ -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 . + +# 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 index 00000000000..ce8a7a703aa --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-0.exp @@ -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 . */ + +# 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 index 00000000000..092d4b20c48 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-1.exp @@ -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 . */ + +# 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 index 00000000000..803d297f70d --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-2.exp @@ -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 . */ + +# 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 index 00000000000..d1307571bfa --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-3.exp @@ -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 . */ + +# 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 index 00000000000..2b84b5dcfc7 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-4.exp @@ -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 . */ + +# 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 index 00000000000..9bc3e9c16fc --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.c @@ -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 . */ + +/* Exercise AArch64's Scalable Vector/Matrix Extension signal frame handling + for GDB. */ + +#include +#include +#include +#include +#include +#include +#include + +#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 index 00000000000..62b90761c39 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.exp.tcl @@ -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 . + +# 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 index 00000000000..835f28950df --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-0.exp @@ -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 . */ + +# 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 index 00000000000..73ec3f67269 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-1.exp @@ -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 . */ + +# 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 index 00000000000..4d223ef4070 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-2.exp @@ -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 . */ + +# 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 index 00000000000..3a26cd36975 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-3.exp @@ -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 . */ + +# 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 index 00000000000..c8e73b7cf73 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-4.exp @@ -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 . */ + +# 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 index 00000000000..7b9f908b256 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-5.exp @@ -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 . */ + +# 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 index 00000000000..7a3d52f4333 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-6.exp @@ -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 . */ + +# 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 index 00000000000..03cff0a0fe8 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-7.exp @@ -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 . */ + +# 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 index 00000000000..2379f3e79b4 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-8.exp @@ -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 . */ + +# 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 index 00000000000..623e75b1f64 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-9.exp @@ -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 . */ + +# 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 index 00000000000..9c844c91c7c --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.c @@ -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 . */ + +/* Exercise various cases of ZA contents not being available for AArch64's + Scalable Matrix Extension. */ + +#include +#include +#include +#include +#include + +#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 index 00000000000..faeec4c2901 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.exp.tcl @@ -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 . + +# 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 index 00000000000..694de0626d2 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-sanity.c @@ -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 . */ + +/* 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 +#include +#include +#include +#include + +#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 index 00000000000..3369976ef9b --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sme-sanity.exp @@ -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 . +# +# 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 index 00000000000..1be691949d2 --- /dev/null +++ b/gdb/testsuite/lib/aarch64-scalable.exp @@ -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 . */ + +# 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 } +# +# or +# +# {BYTE_FPSIMD , 0 } +# +# or +# +# {BYTE_SVE } +# +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 , 0 " + } else { + append data "$byte_fpsimd " + } + } else { + append data "$byte_sve " + } + 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 , 0 }"] + } + } 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 index 00000000000..c123f37e0df --- /dev/null +++ b/gdb/testsuite/lib/aarch64-test-sme.c @@ -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 . */ + +/* 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 +#include +#include +#include +#include +#include + +#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 index 00000000000..4673581b467 --- /dev/null +++ b/gdb/testsuite/lib/aarch64-test-sve.c @@ -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 . */ + +/* 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 +#include +#include +#include +#include +#include + +#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 index 00000000000..cd43a4c4f77 --- /dev/null +++ b/gdb/testsuite/lib/aarch64.exp @@ -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 . */ + +# 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 ". +# +proc 1d_array_value_pattern { byte elements } { + set brace_open "{" + set brace_close "}" + + append data $brace_open $byte + if {$elements > 1} { + append data " " + } + 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 } }". +# +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 " " + } + 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 + } +} diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index de22da8d8a8..c9f1f666eb8 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -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} { -- 2.30.2