* [PATCH v2 0/3] RISC-V Vector Extension support
@ 2026-09-25 17:29 Kirill Radkin
2026-09-25 17:29 ` [PATCH v2 1/3] RISC-V Vector Extension Support Kirill Radkin
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Kirill Radkin @ 2026-09-25 17:29 UTC (permalink / raw)
To: gdb-patches
Cc: Peter Bergner, Sergey Matyukevich, Jerry Zhang Jian,
Heinrich Schuchardt, Andrew Burgess, Palmer Dabbelt
Hi all,
This series adds RISC-V Vector Extension support to native Linux GDB and
gdbserver. It provides access to v0-v31 and the vector CSRs, target
descriptions sized according to VLENB, and support for the vector calling
convention in inferior calls.
It also contains a separate RVV instruction-recording patch for reverse
execution and tests covering register access, CSR printing, and vector and
tuple arguments and return values. The RVV support has been tested at VLEN
values of 64, 128, and 1024, using both system QEMU on Linux and an
OpenOCD + Spike setup.
Jerry Zhang Jian pointed out in an earlier message that the Tcl procedures
needed by the tests were missing. They are now included.
I am continuing to work on this series and plan to send further improvements.
I've CCed Andrew and Palmer since they are listed as RISC-V maintainers in
gdb/MAINTAINERS, and Peter Bergner, Sergey Matyukevich, Jerry Zhang Jian,
and Heinrich Schuchardt because of earlier discussion of this work.
Best regards,
Kirill
Kirill Radkin (3):
RISC-V Vector Extension Support
Reverse execution support for RISC-V Vector Extension
RISC-V Vector Extension Support Testing
gdb/arch/riscv.c | 9 +-
gdb/arch/riscv.h | 18 +-
gdb/features/riscv/rvv.c | 113 ++
gdb/gdbtypes.c | 41 +
gdb/nat/riscv-linux-ptrace.h | 31 +
gdb/nat/riscv-linux-tdesc.c | 35 +
gdb/riscv-linux-nat.c | 164 ++
gdb/riscv-regs.h | 79 +
gdb/riscv-tdep.c | 1369 ++++++++++++++++-
gdb/riscv-tdep.h | 63 +-
...iscv-vector-abi-full-generate-template.txt | 176 +++
.../riscv-vector-abi-full-generate.py | 384 +++++
.../gdb.arch/riscv-vector-abi-full.c | 23 +
.../gdb.arch/riscv-vector-abi-full.exp | 72 +
gdb/testsuite/gdb.arch/riscv-vector-abi.c | 157 ++
gdb/testsuite/gdb.arch/riscv-vector-abi.exp | 247 +++
.../gdb.arch/riscv-vu-availability.c | 67 +
.../gdb.arch/riscv-vu-availability.exp | 72 +
.../gdb.arch/riscv-vu-consitency-checks.c | 79 +
.../gdb.arch/riscv-vu-consitency-checks.exp | 156 ++
gdb/testsuite/gdb.arch/riscv-vu-ctx-print.c | 106 ++
gdb/testsuite/gdb.arch/riscv-vu-ctx-print.exp | 107 ++
gdb/testsuite/gdb.arch/riscv-vu-printout.c | 69 +
gdb/testsuite/gdb.arch/riscv-vu-printout.exp | 92 ++
.../gdb.arch/riscv-vu-rvv-unsupported.c | 23 +
.../gdb.arch/riscv-vu-rvv-unsupported.exp | 46 +
gdb/testsuite/gdb.arch/riscv-vu-rwr.c | 62 +
gdb/testsuite/gdb.arch/riscv-vu-rwr.exp | 173 +++
.../gdb.arch/riscv-vu-side-effects.c | 86 ++
.../gdb.arch/riscv-vu-side-effects.exp | 162 ++
gdb/testsuite/lib/gdb.exp | 124 ++
gdb/testsuite/lib/riscv64-rvv-lib.exp | 347 +++++
gdbserver/linux-riscv-low.cc | 129 +-
gdbsupport/common-utils.h | 22 +
include/opcode/riscv-opc.h | 79 +
include/opcode/riscv.h | 10 +
36 files changed, 4832 insertions(+), 160 deletions(-)
create mode 100644 gdb/features/riscv/rvv.c
create mode 100644 gdb/nat/riscv-linux-ptrace.h
create mode 100644 gdb/riscv-regs.h
create mode 100644 gdb/testsuite/gdb.arch/riscv-vector-abi-full-generate-template.txt
create mode 100644 gdb/testsuite/gdb.arch/riscv-vector-abi-full-generate.py
create mode 100644 gdb/testsuite/gdb.arch/riscv-vector-abi-full.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vector-abi-full.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vector-abi.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vector-abi.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-availability.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-availability.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-consitency-checks.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-consitency-checks.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-ctx-print.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-ctx-print.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-printout.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-printout.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-rvv-unsupported.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-rvv-unsupported.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-rwr.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-rwr.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-side-effects.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-side-effects.exp
create mode 100644 gdb/testsuite/lib/riscv64-rvv-lib.exp
base-commit: ba3e439f17aabdb5b1a9ca61646f9c22604ab259
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/3] RISC-V Vector Extension Support
2026-09-25 17:29 [PATCH v2 0/3] RISC-V Vector Extension support Kirill Radkin
@ 2026-09-25 17:29 ` Kirill Radkin
2026-09-25 17:29 ` [PATCH v2 2/3] Reverse execution support for RISC-V Vector Extension Kirill Radkin
2026-09-25 17:29 ` [PATCH v2 3/3] RISC-V Vector Extension Support Testing Kirill Radkin
2 siblings, 0 replies; 4+ messages in thread
From: Kirill Radkin @ 2026-09-25 17:29 UTC (permalink / raw)
To: gdb-patches
Cc: Peter Bergner, Sergey Matyukevich, Jerry Zhang Jian,
Heinrich Schuchardt, Andrew Burgess, Palmer Dabbelt
This patch adds support for the RISC-V Vector Extension (RVV) and the RISC-V
Vector ABI to GDB, for both gdb and gdbserver (so, it's available for cross and
native debugging). It is now possible to inspect and modify vector registers
directly. Furthermore, GDB supports evaluating variables with RISC-V vector
types (such as vint32m4_t) and calling functions that take vector arguments
using the print and call GDB commands. Patch also includes tests targeting RVV
support, tested on targets with different vlen (64, 128, 1024). Implementation
is tested on system QEMU (Linux) and on OpenOCD + spike configuration.
---
gdb/arch/riscv.c | 9 +-
gdb/arch/riscv.h | 18 +-
gdb/features/riscv/rvv.c | 113 +++++
gdb/gdbtypes.c | 41 ++
gdb/nat/riscv-linux-ptrace.h | 31 ++
gdb/nat/riscv-linux-tdesc.c | 35 ++
gdb/riscv-linux-nat.c | 164 +++++++
gdb/riscv-regs.h | 79 ++++
gdb/riscv-tdep.c | 876 ++++++++++++++++++++++++++++++++---
gdb/riscv-tdep.h | 63 +--
gdbserver/linux-riscv-low.cc | 129 ++++--
gdbsupport/common-utils.h | 22 +
12 files changed, 1422 insertions(+), 158 deletions(-)
create mode 100644 gdb/features/riscv/rvv.c
create mode 100644 gdb/nat/riscv-linux-ptrace.h
create mode 100644 gdb/riscv-regs.h
diff --git a/gdb/arch/riscv.c b/gdb/arch/riscv.c
index c0e6c6aec63..96a68bf1654 100644
--- a/gdb/arch/riscv.c
+++ b/gdb/arch/riscv.c
@@ -22,6 +22,7 @@
#include "../features/riscv/64bit-cpu.c"
#include "../features/riscv/32bit-fpu.c"
#include "../features/riscv/64bit-fpu.c"
+#include "../features/riscv/rvv.c"
#include "../features/riscv/rv32e-xregs.c"
#ifndef GDBSERVER
@@ -82,11 +83,9 @@ riscv_create_target_description (const struct riscv_gdbarch_features features)
else if (features.flen == 8)
regnum = create_feature_riscv_64bit_fpu (tdesc.get (), regnum);
- /* Currently GDB only supports vector features coming from remote
- targets. We don't support creating vector features on native targets
- (yet). */
- if (features.vlen != 0)
- error (_("unable to create vector feature"));
+ if (features.vlenb != 0)
+ regnum = create_feature_riscv_rvv (tdesc.get (), features.vlenb,
+ features.xlen);
return tdesc;
}
diff --git a/gdb/arch/riscv.h b/gdb/arch/riscv.h
index 1443bc20a7d..0261d4d0f9e 100644
--- a/gdb/arch/riscv.h
+++ b/gdb/arch/riscv.h
@@ -51,7 +51,7 @@ struct riscv_gdbarch_features
target should be 16 and 4 for an embedded subset compliant target (with
'Zve32*' extension), but GDB doesn't currently mind, and will accept any
vector size. */
- int vlen = 0;
+ int vlenb = 0;
/* When true this target is RV32E. */
bool embedded = false;
@@ -68,9 +68,8 @@ struct riscv_gdbarch_features
/* Equality operator. */
bool operator== (const struct riscv_gdbarch_features &rhs) const
{
- return (xlen == rhs.xlen && flen == rhs.flen
- && embedded == rhs.embedded && vlen == rhs.vlen
- && has_fflags_reg == rhs.has_fflags_reg
+ return (xlen == rhs.xlen && flen == rhs.flen && embedded == rhs.embedded
+ && vlenb == rhs.vlenb && has_fflags_reg == rhs.has_fflags_reg
&& has_frm_reg == rhs.has_frm_reg
&& has_fcsr_reg == rhs.has_fcsr_reg);
}
@@ -84,13 +83,10 @@ struct riscv_gdbarch_features
/* Used by std::unordered_map to hash feature sets. */
std::size_t hash () const noexcept
{
- std::size_t val = ((embedded ? 1 : 0) << 10
- | (has_fflags_reg ? 1 : 0) << 11
- | (has_frm_reg ? 1 : 0) << 12
- | (has_fcsr_reg ? 1 : 0) << 13
- | (xlen & 0x1f) << 5
- | (flen & 0x1f) << 0
- | (vlen & 0x3fff) << 14);
+ std::size_t val
+ = ((embedded ? 1 : 0) << 10 | (has_fflags_reg ? 1 : 0) << 11
+ | (has_frm_reg ? 1 : 0) << 12 | (has_fcsr_reg ? 1 : 0) << 13
+ | (xlen & 0x1f) << 5 | (flen & 0x1f) << 0 | (vlenb & 0x3fff) << 14);
return val;
}
};
diff --git a/gdb/features/riscv/rvv.c b/gdb/features/riscv/rvv.c
new file mode 100644
index 00000000000..060cb5a44f2
--- /dev/null
+++ b/gdb/features/riscv/rvv.c
@@ -0,0 +1,113 @@
+/* Copyright (C) 2026 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "gdbsupport/gdb_assert.h"
+#include "gdbsupport/tdesc.h"
+#include "gdb/riscv-regs.h"
+#include <vector>
+
+/* This file is NOT auto generated from xml.
+ 'create_feature_riscv_rvv' creates a RISCV Vector Extension feature.
+ 'vlenb' is a vector register size in bytes */
+
+struct vector_field_type_info
+{
+ const char *element_type_name;
+ const char *vector_type_name;
+ int element_count;
+};
+
+static void
+create_vector_register_type (tdesc_feature *feature,
+ std::vector<vector_field_type_info> &types_info,
+ const char *type_name)
+{
+ tdesc_type *element_type;
+
+ for (auto &&type_info : types_info)
+ {
+ if (type_info.element_count == -1)
+ continue;
+ element_type = tdesc_named_type (feature, type_info.element_type_name);
+ tdesc_create_vector (feature, type_info.vector_type_name, element_type,
+ type_info.element_count);
+ }
+
+ tdesc_type_with_fields *type_with_fields = tdesc_create_union (feature,
+ type_name);
+
+ for (auto &&type_info : types_info)
+ {
+ if (type_info.element_count == -1)
+ continue;
+ element_type = tdesc_named_type (feature, type_info.vector_type_name);
+ tdesc_add_field (type_with_fields, type_info.vector_type_name,
+ element_type);
+ }
+}
+
+static int
+create_feature_riscv_rvv (target_desc *result, int vlenb, int xlen)
+{
+ gdb_assert (result);
+ gdb_assert (xlen == 4 || xlen == 8);
+ gdb_assert (vlenb >= 4 && ((vlenb & (vlenb - 1)) == 0));
+
+ int v_bitsize = 8 * vlenb;
+ int x_bitsize = 8 * xlen;
+
+ tdesc_feature *csr_feature = tdesc_create_feature (result,
+ "org.gnu.gdb.riscv.csr");
+ tdesc_create_reg (csr_feature, "vstart", RISCV_CSR_VSTART_REGNUM, 1, NULL,
+ x_bitsize, "int");
+ tdesc_create_reg (csr_feature, "vcsr", RISCV_CSR_VCSR_REGNUM, 1, NULL,
+ x_bitsize, "int");
+ tdesc_create_reg (csr_feature, "vl", RISCV_CSR_VL_REGNUM, 1, NULL, x_bitsize,
+ "int");
+ tdesc_create_reg (csr_feature, "vtype", RISCV_CSR_VTYPE_REGNUM, 1, NULL,
+ x_bitsize, "int");
+ tdesc_create_reg (csr_feature, "vlenb", RISCV_CSR_VLENB_REGNUM, 1, NULL,
+ x_bitsize, "int");
+
+ tdesc_feature *vector_feature
+ = tdesc_create_feature (result, "org.gnu.gdb.riscv.vector");
+
+ std::vector<vector_field_type_info> elements_types_info
+ = { { "int8", "i8", vlenb },
+ { "int16", "i16", vlenb / 2 },
+ { "int32", "i32", vlenb / 4 },
+ { "int64", "i64", (vlenb >= 8) ? vlenb / 8 : -1 },
+ { "ieee_half", "half", vlenb / 2 },
+ { "ieee_single", "f32", vlenb / 4 },
+ { "ieee_double", "f64", (vlenb >= 8) ? vlenb / 8 : -1 } };
+
+ create_vector_register_type (vector_feature, elements_types_info, "rvv");
+
+ int regnum = RISCV_V0_REGNUM;
+
+ constexpr const char *vec_reg_names[]
+ = { "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
+ "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
+ "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
+ "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" };
+
+ for (int i = 0; i < 32; ++i)
+ tdesc_create_reg (vector_feature, vec_reg_names[i], regnum++, 1, NULL,
+ v_bitsize, "rvv");
+
+ return regnum;
+}
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 4b6c01910f4..34581d65bb4 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -1977,6 +1977,21 @@ is_dynamic_type_internal_1 (struct type *type,
}
}
break;
+
+ case TYPE_CODE_FUNC:
+ {
+ /* If the type of value returned by function is dynamic, we should mark
+ func as dynamic to later resolve this dynamic type */
+ if (type->target_type ()
+ && is_dynamic_type_internal_1 (type->target_type (), false))
+ return true;
+
+ /* Same for function arguments */
+ for (int i = 0; i < type->num_fields (); ++i)
+ if (is_dynamic_type_internal_1 (type->field (i).type (), false))
+ return true;
+ }
+ break;
}
return false;
@@ -2742,6 +2757,25 @@ resolve_dynamic_struct (struct type *type,
return resolved_type;
}
+/* Resolve dynamic function's arguments/returned value types */
+static struct type *
+resolve_dynamic_func (struct type *type, const property_addr_info *addr_stack,
+ const frame_info_ptr &frame, bool top_level)
+{
+ gdb_assert (type->code () == TYPE_CODE_FUNC);
+
+ struct type *resolved_type = copy_type (type);
+
+ resolved_type->set_target_type (resolve_dynamic_type_internal (
+ type->target_type (), addr_stack, frame, top_level));
+
+ for (int i = 0; i < resolved_type->num_fields (); i++)
+ resolved_type->field (i).set_type (resolve_dynamic_type_internal (
+ resolved_type->field (i).type (), addr_stack, frame, top_level));
+
+ return resolved_type;
+}
+
/* Worker for resolved_dynamic_type. */
static struct type *
@@ -2840,6 +2874,13 @@ resolve_dynamic_type_internal (struct type *type,
case TYPE_CODE_STRUCT:
resolved_type = resolve_dynamic_struct (type, addr_stack, frame);
break;
+
+ case TYPE_CODE_FUNC:
+ /* If func was marked as dynamic, that means that it have dynamic
+ arguments or returned value*/
+ resolved_type = resolve_dynamic_func (type, addr_stack, frame,
+ top_level);
+ break;
}
}
diff --git a/gdb/nat/riscv-linux-ptrace.h b/gdb/nat/riscv-linux-ptrace.h
new file mode 100644
index 00000000000..f021b263844
--- /dev/null
+++ b/gdb/nat/riscv-linux-ptrace.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2026 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef NAT_RISCV_LINUX_HW_PTRACE_H
+#define NAT_RISCV_LINUX_HW_PTRACE_H
+
+struct __riscv_v_regset_state
+{
+ unsigned long vstart;
+ unsigned long vl;
+ unsigned long vtype;
+ unsigned long vcsr;
+ unsigned long vlenb;
+ char vreg[];
+};
+
+#endif // NAT_RISCV_LINUX_HW_PTRACE_H
diff --git a/gdb/nat/riscv-linux-tdesc.c b/gdb/nat/riscv-linux-tdesc.c
index 1cb3129ba6d..a3e0fe383bb 100644
--- a/gdb/nat/riscv-linux-tdesc.c
+++ b/gdb/nat/riscv-linux-tdesc.c
@@ -30,6 +30,27 @@
# define NFPREG 33
#endif
+/* RISC-V Hardware Probing Syscall Number. */
+#ifndef NR_riscv_hwprobe
+#ifndef NR_arch_specific_syscall
+#define NR_arch_specific_syscall 244
+#endif
+#define NR_riscv_hwprobe (NR_arch_specific_syscall + 14)
+#endif
+
+#ifndef RISCV_HWPROBE_KEY_IMA_EXT_0
+/* A bitmask containing the supported extensions. */
+#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
+/* Bit that indicate RISC-V Vector extension support in Linux. */
+#define RISCV_HWPROBE_EXT_ZVE32X (1ULL << 37)
+#endif
+
+struct riscv_hwprobe
+{
+ int64_t key;
+ uint64_t value;
+};
+
/* See nat/riscv-linux-tdesc.h. */
struct riscv_gdbarch_features
@@ -78,5 +99,19 @@ riscv_linux_read_features (int tid)
break;
}
+ features.vlenb = 0;
+
+ static struct riscv_hwprobe query[] = { { RISCV_HWPROBE_KEY_IMA_EXT_0, 0 } };
+
+ /* All possible vector extensions depends on Zve32x, and it's availability is
+ a minimum requirement. */
+ if ((syscall (NR_riscv_hwprobe, query, 1, 0, NULL, 0) == 0)
+ && (query[0].value & RISCV_HWPROBE_EXT_ZVE32X))
+ {
+ int reg = 0;
+ asm volatile ("csrr %[vlenb], vlenb" : [vlenb] "=r"(reg));
+ features.vlenb = reg;
+ }
+
return features;
}
diff --git a/gdb/riscv-linux-nat.c b/gdb/riscv-linux-nat.c
index e1e81ad50c4..aecb777b7ce 100644
--- a/gdb/riscv-linux-nat.c
+++ b/gdb/riscv-linux-nat.c
@@ -24,6 +24,7 @@
#include "elf/common.h"
+#include "nat/riscv-linux-ptrace.h"
#include "nat/riscv-linux-tdesc.h"
#include <sys/ptrace.h>
@@ -132,6 +133,64 @@ supply_fpregset (struct regcache *regcache, const prfpregset_t *fpregs)
supply_fpregset_regnum (regcache, fpregs, -1);
}
+static void
+supply_vecregset_regnum (regcache *regcache,
+ const __riscv_v_regset_state *vecregs, int regnum)
+{
+ gdb_assert (vecregs->vlenb > 0);
+ if ((regnum >= RISCV_V0_REGNUM && regnum <= RISCV_V31_REGNUM))
+ {
+ regcache->raw_supply (regnum,
+ vecregs->vreg
+ + vecregs->vlenb * (regnum - RISCV_V0_REGNUM));
+ return;
+ }
+
+ if (regnum == RISCV_CSR_VSTART_REGNUM)
+ {
+ regcache->raw_supply (regnum, &vecregs->vstart);
+ return;
+ }
+
+ if (regnum == RISCV_CSR_VCSR_REGNUM)
+ {
+ regcache->raw_supply (regnum, &vecregs->vcsr);
+ return;
+ }
+
+ if (regnum == RISCV_CSR_VL_REGNUM)
+ {
+ regcache->raw_supply (regnum, &vecregs->vl);
+ return;
+ }
+
+ if (regnum == RISCV_CSR_VTYPE_REGNUM)
+ {
+ regcache->raw_supply (regnum, &vecregs->vtype);
+ return;
+ }
+
+ if (regnum == RISCV_CSR_VLENB_REGNUM)
+ {
+ regcache->raw_supply (regnum, &vecregs->vlenb);
+ return;
+ }
+
+ if (regnum == -1)
+ {
+ regcache->raw_supply (RISCV_CSR_VSTART_REGNUM, &vecregs->vstart);
+ regcache->raw_supply (RISCV_CSR_VCSR_REGNUM, &vecregs->vcsr);
+ regcache->raw_supply (RISCV_CSR_VL_REGNUM, &vecregs->vl);
+ regcache->raw_supply (RISCV_CSR_VTYPE_REGNUM, &vecregs->vtype);
+ regcache->raw_supply (RISCV_CSR_VLENB_REGNUM, &vecregs->vlenb);
+
+ for (int i = RISCV_V0_REGNUM; i <= RISCV_V31_REGNUM; i++)
+ regcache->raw_supply (i, vecregs->vreg
+ + vecregs->vlenb * (i - RISCV_V0_REGNUM));
+ return;
+ }
+}
+
/* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1)
from REGCACHE into regset GREGS. */
@@ -195,6 +254,64 @@ fill_fpregset (const struct regcache *regcache, prfpregset_t *fpregs,
}
}
+static void
+fill_vecregset_regnum (regcache *regcache, __riscv_v_regset_state *vecregs,
+ int regnum)
+{
+ if ((regnum >= RISCV_V0_REGNUM && regnum <= RISCV_V31_REGNUM))
+ {
+ regcache->raw_collect (regnum,
+ vecregs->vreg
+ + vecregs->vlenb * (regnum - RISCV_V0_REGNUM));
+ return;
+ }
+
+ if (regnum == RISCV_CSR_VSTART_REGNUM)
+ {
+ regcache->raw_collect (regnum, &vecregs->vstart);
+ return;
+ }
+
+ if (regnum == RISCV_CSR_VCSR_REGNUM)
+ {
+ regcache->raw_collect (regnum, &vecregs->vcsr);
+ return;
+ }
+
+ if (regnum == RISCV_CSR_VL_REGNUM)
+ {
+ regcache->raw_collect (regnum, &vecregs->vl);
+ return;
+ }
+
+ if (regnum == RISCV_CSR_VTYPE_REGNUM)
+ {
+ regcache->raw_collect (regnum, &vecregs->vtype);
+ return;
+ }
+
+ if (regnum == RISCV_CSR_VLENB_REGNUM)
+ {
+ regcache->raw_collect (regnum, &vecregs->vlenb);
+ return;
+ }
+
+ if (regnum == -1)
+ {
+ regcache->raw_collect (RISCV_CSR_VSTART_REGNUM, &vecregs->vstart);
+ regcache->raw_collect (RISCV_CSR_VCSR_REGNUM, &vecregs->vcsr);
+ regcache->raw_collect (RISCV_CSR_VL_REGNUM, &vecregs->vl);
+ regcache->raw_collect (RISCV_CSR_VTYPE_REGNUM, &vecregs->vtype);
+ regcache->raw_collect (RISCV_CSR_VLENB_REGNUM, &vecregs->vlenb);
+
+ for (int i = RISCV_V0_REGNUM; i <= RISCV_V31_REGNUM; i++)
+ regcache->raw_collect (i, vecregs->vreg
+ + vecregs->vlenb * (i - RISCV_V0_REGNUM));
+
+ return;
+ }
+}
+
/* Return a target description for the current target. */
const struct target_desc *
@@ -261,6 +378,29 @@ riscv_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum)
regcache->raw_supply_zeroed (RISCV_CSR_MISA_REGNUM);
}
+ if (riscv_is_vpr_or_vcsr (regnum) || (regnum == -1))
+ {
+ int vecreg_size = register_size (regcache->arch (), RISCV_V0_REGNUM);
+ std::vector<char> vregs_buff (sizeof (__riscv_v_regset_state)
+ + vecreg_size * 32);
+
+ __riscv_v_regset_state *vregs_state
+ = (__riscv_v_regset_state *) vregs_buff.data ();
+
+ iovec iov;
+ iov.iov_base = vregs_state;
+ iov.iov_len = sizeof (struct __riscv_v_regset_state) + 32 * vecreg_size;
+
+ if (ptrace (PTRACE_GETREGSET, tid, NT_RISCV_VECTOR,
+ (PTRACE_TYPE_ARG3) &iov)
+ == 0
+ && vregs_state->vlenb > 0)
+ {
+ gdb_assert (vregs_state->vlenb == vecreg_size);
+ supply_vecregset_regnum (regcache, vregs_state, regnum);
+ }
+ }
+
/* Access to other CSRs has potential security issues, don't support them for
now. */
}
@@ -323,6 +463,30 @@ riscv_linux_nat_target::store_registers (struct regcache *regcache, int regnum)
}
}
+ if (riscv_is_vpr_or_vcsr (regnum) || (regnum == -1))
+ {
+ int vecreg_size = register_size (regcache->arch (), RISCV_V0_REGNUM);
+ std::vector<char> vregs_buff (sizeof (__riscv_v_regset_state)
+ + vecreg_size * 32);
+
+ __riscv_v_regset_state *vregs_state
+ = (__riscv_v_regset_state *) vregs_buff.data ();
+
+ iovec iov;
+ iov.iov_base = vregs_state;
+ iov.iov_len = sizeof (struct __riscv_v_regset_state) + 32 * vecreg_size;
+
+ if (ptrace (PTRACE_GETREGSET, tid, NT_RISCV_VECTOR,
+ (PTRACE_TYPE_ARG3) &iov)
+ == 0)
+ {
+ fill_vecregset_regnum (regcache, vregs_state, regnum);
+
+ ptrace (PTRACE_SETREGSET, tid, NT_RISCV_VECTOR,
+ (PTRACE_TYPE_ARG3) &iov);
+ }
+ }
+
/* Access to CSRs has potential security issues, don't support them for
now. */
}
diff --git a/gdb/riscv-regs.h b/gdb/riscv-regs.h
new file mode 100644
index 00000000000..76810d3ef4b
--- /dev/null
+++ b/gdb/riscv-regs.h
@@ -0,0 +1,79 @@
+/* Target-dependent header for the RISC-V architecture, for GDB, the
+ GNU Debugger.
+
+ Copyright (C) 2026 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef GDB_RISCV_REGS_H
+#define GDB_RISCV_REGS_H
+
+/* RiscV register numbers. */
+enum
+{
+ RISCV_ZERO_REGNUM = 0, /* Read-only register, always 0. */
+ RISCV_RA_REGNUM = 1, /* Return Address. */
+ RISCV_SP_REGNUM = 2, /* Stack Pointer. */
+ RISCV_GP_REGNUM = 3, /* Global Pointer. */
+ RISCV_TP_REGNUM = 4, /* Thread Pointer. */
+ RISCV_FP_REGNUM = 8, /* Frame Pointer. */
+ RISCV_A0_REGNUM = 10, /* First argument. */
+ RISCV_A1_REGNUM = 11, /* Second argument. */
+ RISCV_A2_REGNUM = 12, /* Third argument. */
+ RISCV_A3_REGNUM = 13, /* Forth argument. */
+ RISCV_A4_REGNUM = 14, /* Fifth argument. */
+ RISCV_A5_REGNUM = 15, /* Sixth argument. */
+ RISCV_A7_REGNUM = 17, /* Register to pass syscall number. */
+ RISCV_PC_REGNUM = 32, /* Program Counter. */
+
+ RISCV_NUM_INTEGER_REGS = 32,
+
+ RISCV_FIRST_FP_REGNUM = 33, /* First Floating Point Register */
+ RISCV_FA0_REGNUM = 43,
+ RISCV_FA1_REGNUM = RISCV_FA0_REGNUM + 1,
+ RISCV_LAST_FP_REGNUM = 64, /* Last Floating Point Register */
+
+ RISCV_FIRST_CSR_REGNUM = 65, /* First CSR */
+#define DECLARE_CSR(name, num, class, define_version, abort_version) \
+ RISCV_##num##_REGNUM = RISCV_FIRST_CSR_REGNUM + num,
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+ RISCV_LAST_CSR_REGNUM = 4160,
+ RISCV_CSR_LEGACY_MISA_REGNUM = 0xf10 + RISCV_FIRST_CSR_REGNUM,
+
+ RISCV_PRIV_REGNUM = 4161,
+
+ RISCV_V0_REGNUM,
+
+ RISCV_V31_REGNUM = RISCV_V0_REGNUM + 31,
+
+ RISCV_LAST_REGNUM = RISCV_V31_REGNUM
+};
+
+/* RiscV DWARF register numbers. */
+enum
+{
+ RISCV_DWARF_REGNUM_X0 = 0,
+ RISCV_DWARF_REGNUM_X31 = 31,
+ RISCV_DWARF_REGNUM_F0 = 32,
+ RISCV_DWARF_REGNUM_F31 = 63,
+ RISCV_DWARF_REGNUM_V0 = 96,
+ RISCV_DWARF_REGNUM_V31 = 127,
+ RISCV_DWARF_FIRST_CSR = 4096,
+ RISCV_DWARF_LAST_CSR = 8191,
+};
+
+#endif /* GDB_RISCV_REGS_H */
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index 100a44cddf3..12bc51beb38 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -57,6 +57,12 @@
#include "record-full.h"
#include "riscv-ravenscar-thread.h"
+#include <array>
+#include <charconv>
+#include <list>
+#include <numeric>
+#include <optional>
+#include <regex>
#include <vector>
/* The stack must be 16-byte aligned. */
@@ -660,10 +666,16 @@ struct riscv_vector_feature : public riscv_register_feature
RISCV_V0_REGNUM + 31. */
const char *register_name (int regnum) const
{
- gdb_assert (regnum >= RISCV_V0_REGNUM
- && regnum <= RISCV_V0_REGNUM + 31);
- regnum -= RISCV_V0_REGNUM;
- return m_registers[regnum].names[0];
+ gdb_assert (regnum >= RISCV_V0_REGNUM && regnum <= RISCV_V0_REGNUM + 31);
+
+ const auto reg_info_it = std::find_if (m_registers.begin (),
+ m_registers.end (),
+ [regnum] (const auto ®_info) {
+ return reg_info.regnum == regnum;
+ });
+ if (reg_info_it == m_registers.end ())
+ gdb_assert_not_reached ("Incorrect vector register number %d", regnum);
+ return reg_info_it->names.front ();
}
/* Check this feature within TDESC, record the registers from this
@@ -679,7 +691,7 @@ struct riscv_vector_feature : public riscv_register_feature
feature set and return. */
if (feature_vector == nullptr)
{
- features->vlen = 0;
+ features->vlenb = 0;
return true;
}
@@ -696,6 +708,9 @@ struct riscv_vector_feature : public riscv_register_feature
int vector_bitsize = -1;
for (const auto ® : m_registers)
{
+ if (reg.regnum < RISCV_V0_REGNUM || reg.regnum > RISCV_V31_REGNUM)
+ continue;
+
int reg_bitsize = -1;
for (const char *name : reg.names)
{
@@ -712,7 +727,7 @@ struct riscv_vector_feature : public riscv_register_feature
return false;
}
- features->vlen = (vector_bitsize / 8);
+ features->vlenb = (vector_bitsize / 8);
return true;
}
};
@@ -793,6 +808,58 @@ riscv_abi_xlen (struct gdbarch *gdbarch)
/* See riscv-tdep.h. */
+int
+riscv_isa_vlenb (struct gdbarch *gdbarch)
+{
+ riscv_gdbarch_tdep *tdep = gdbarch_tdep<riscv_gdbarch_tdep> (gdbarch);
+ return tdep->isa_features.vlenb;
+}
+
+/* Return true if the target for GDBARCH has vector hardware. */
+
+static bool
+riscv_has_vector_regs (struct gdbarch *gdbarch)
+{
+ return (riscv_isa_vlenb (gdbarch) > 0);
+}
+
+/* Return true if REGNO is a vector GPR. */
+
+static bool
+riscv_is_vector_gpr (int regno)
+{
+ return (regno >= RISCV_V0_REGNUM && regno <= RISCV_V31_REGNUM);
+}
+
+/* Return true if REGNO is a vector CSR. */
+
+static bool
+riscv_is_vector_rw_csr (int regno)
+{
+ return (regno == RISCV_CSR_VSTART_REGNUM || regno == RISCV_CSR_VCSR_REGNUM
+ || regno == RISCV_CSR_VL_REGNUM || regno == RISCV_CSR_VTYPE_REGNUM);
+}
+
+/* Return true if REGNO is a vector GPR or CSR. */
+
+static bool
+riscv_is_vector_save_restore_regno (int regno)
+{
+ return riscv_is_vector_gpr (regno) || riscv_is_vector_rw_csr (regno);
+}
+
+/* Return true if GDBARCH is using vector hardware ABI. */
+
+static bool
+riscv_has_vector_abi (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch);
+ riscv_gdbarch_tdep *tdep = gdbarch_tdep<riscv_gdbarch_tdep> (gdbarch);
+ return tdep->abi_features.vlenb > 0;
+}
+
+/* See riscv-tdep.h. */
+
int
riscv_isa_flen (struct gdbarch *gdbarch)
{
@@ -1052,7 +1119,7 @@ riscv_pseudo_register_write (struct gdbarch *gdbarch,
static bool
riscv_cannot_store_register (struct gdbarch *gdbarch, int regnum)
{
- return regnum == RISCV_ZERO_REGNUM;
+ return regnum == RISCV_ZERO_REGNUM || regnum == RISCV_CSR_VLENB_REGNUM;
}
/* Construct a type for 64-bit FP registers. */
@@ -1200,7 +1267,7 @@ riscv_print_one_register_info (struct gdbarch *gdbarch,
{
riscv_gdbarch_tdep *tdep = gdbarch_tdep<riscv_gdbarch_tdep> (gdbarch);
- /* Print the register in hex. */
+ /* Print the register in hex, exclude vector registers. */
value_print_options opts = get_formatted_print_options ('x');
opts.deref_ref = true;
common_val_print (val, file, 0, opts, current_language);
@@ -1330,17 +1397,46 @@ riscv_print_one_register_info (struct gdbarch *gdbarch,
else
gdb_printf (file, "\tprv:%d [INVALID]", priv);
}
- else
+ else if (regnum == RISCV_CSR_VTYPE_REGNUM)
{
- /* If not a vector register, print it also according to its
- natural format. */
- if (regtype->is_vector () == 0)
- {
- opts = get_user_print_options ();
- opts.deref_ref = true;
- gdb_printf (file, "\t");
- common_val_print (val, file, 0, opts, current_language);
- }
+ LONGEST d = value_as_long (val);
+ // Values are decoded according to RISC-V Vector Specification
+ unsigned lmul_val = d & 0x7;
+ const char *decoded_lmul_variants[]
+ = { "1", "2", "4", "8", "Reserved", "1/8", "1/4", "1/2" };
+ unsigned sew_val = (d >> 3) & 0x7;
+ const char *decoded_sew_variants[] = { "e8", "e16",
+ "e32", "e64",
+ "Reserved", "Reserved",
+ "Reserved", "Reserved" };
+ unsigned vta = (d >> 6) & 0x1;
+ const char *decoded_vta_variants[] = { "tu", "ta" };
+ unsigned vma = (d >> 7) & 0x1;
+ const char *decoded_vma_variants[] = { "mu", "ma" };
+ int size = register_size (gdbarch, regnum);
+ unsigned xlen = size * 8;
+ unsigned vill = (d >> (xlen - 1)) & 0x1;
+ gdb_printf (file,
+ "\tLMUL:%u (%s) SEW:%u (%s) vta:%u (%s) vma:%u "
+ "(%s) vill:%u",
+ lmul_val, decoded_lmul_variants[lmul_val], sew_val,
+ decoded_sew_variants[sew_val], vta,
+ decoded_vta_variants[vta], vma,
+ decoded_vma_variants[vma], vill);
+ }
+ else if (regnum == RISCV_CSR_VCSR_REGNUM)
+ {
+ LONGEST d = value_as_long (val);
+ unsigned vxsat = d & 1;
+ unsigned vxrm = (d >> 1) & 0b11;
+ gdb_printf (file, "\tVXSAT:%u VXRM:%u", vxsat, vxrm);
+ }
+ else if (regtype->is_vector () == 0)
+ {
+ opts = get_user_print_options ();
+ opts.deref_ref = true;
+ gdb_printf (file, "\t");
+ common_val_print (val, file, 0, opts, current_language);
}
}
}
@@ -1433,21 +1529,22 @@ riscv_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
return false;
}
else if (reggroup == float_reggroup)
- return (riscv_is_fp_regno_p (regnum)
- || regnum == RISCV_CSR_FCSR_REGNUM
- || regnum == tdep->fflags_regnum
- || regnum == tdep->frm_regnum);
+ return (riscv_is_fp_regno_p (regnum) || regnum == RISCV_CSR_FCSR_REGNUM
+ || regnum == tdep->fflags_regnum || regnum == tdep->frm_regnum);
else if (reggroup == general_reggroup)
return regnum < RISCV_FIRST_FP_REGNUM;
else if (reggroup == restore_reggroup || reggroup == save_reggroup)
{
if (riscv_has_fp_regs (gdbarch))
- return (regnum <= RISCV_LAST_FP_REGNUM
- || regnum == RISCV_CSR_FCSR_REGNUM
- || regnum == tdep->fflags_regnum
- || regnum == tdep->frm_regnum);
- else
- return regnum < RISCV_FIRST_FP_REGNUM;
+ if (riscv_is_fp_regno_p (regnum) || regnum == RISCV_CSR_FCSR_REGNUM
+ || regnum == tdep->fflags_regnum || regnum == tdep->frm_regnum)
+ return 1;
+
+ if (riscv_has_vector_regs (gdbarch)
+ && riscv_is_vector_save_restore_regno (regnum))
+ return 1;
+
+ return regnum < RISCV_FIRST_FP_REGNUM;
}
else if (reggroup == system_reggroup || reggroup == csr_reggroup)
{
@@ -1460,7 +1557,7 @@ riscv_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
return false;
}
else if (reggroup == vector_reggroup)
- return (regnum >= RISCV_V0_REGNUM && regnum <= RISCV_V31_REGNUM);
+ return riscv_is_vpr_or_vcsr (regnum);
else
return false;
}
@@ -2645,18 +2742,25 @@ struct riscv_arg_info
{
/* What type of location this is. */
enum location_type
- {
- /* Argument passed in a register. */
- in_reg,
+ {
+ /* Argument passed in a register. */
+ in_reg,
+
+ /* Argument passed in several regs. (For now, used for Vector registers.)
+ The first register in the sequence of registers (used for passing
+ arguments) is passed through the first location (see the comment above
+ struct location), and the last one is passed through the second
+ location. */
+ in_several_regs,
- /* Argument passed as an on stack argument. */
- on_stack,
+ /* Argument passed as an on stack argument. */
+ on_stack,
- /* Argument passed by reference. The second location is always
- valid for a BY_REF argument, and describes where the address
- of the BY_REF argument should be placed. */
- by_ref
- } loc_type;
+ /* Argument passed by reference. The second location is always
+ valid for a BY_REF argument, and describes where the address
+ of the BY_REF argument should be placed. */
+ by_ref
+ } loc_type;
/* Information that depends on the location type. */
union
@@ -2712,6 +2816,90 @@ struct riscv_arg_reg
int last_regnum;
};
+struct riscv_vector_arg_reg_interval
+{
+ int first;
+ int last;
+};
+
+struct riscv_vector_arg_reg
+{
+ riscv_vector_arg_reg (int first, int last)
+ : available_intervals { { first, last } }
+ {
+ /* Nothing. */
+ }
+
+ int get_interval_start (int count, int NFIELDS = 1)
+ {
+ gdb_assert (count % NFIELDS == 0);
+
+ int LMUL = count / NFIELDS;
+ for (auto cur_interval = available_intervals.begin ();
+ cur_interval != available_intervals.end (); ++cur_interval)
+ {
+ int cur_first = cur_interval->first;
+ int cur_last = cur_interval->last;
+ if ((cur_first - RISCV_V0_REGNUM) % LMUL
+ != 0) /* According to RISC-V Vector ABI,
+ first register number should be
+ a multiple of LMUL */
+ {
+ cur_first -= (cur_first - RISCV_V0_REGNUM) % LMUL;
+ cur_first += LMUL;
+ }
+
+ if ((cur_last - cur_first + 1) >= count)
+ {
+ if (cur_first > cur_interval->first)
+ {
+ available_intervals.insert (cur_interval,
+ { cur_interval->first,
+ cur_first - 1 });
+ }
+
+ cur_interval->first = cur_first + count;
+
+ return cur_first;
+ }
+ }
+
+ return -1;
+ }
+
+ int try_use_v0 ()
+ {
+ if (is_v0_used)
+ return get_interval_start (1);
+ else
+ {
+ is_v0_used = true;
+ return RISCV_V0_REGNUM;
+ }
+ }
+
+ bool is_v0_used = false;
+
+ std::list<riscv_vector_arg_reg_interval> available_intervals;
+
+ /* From RISCV-ABI, Standard Vector Calling Convention Variant:
+ The rules for passing vector arguments are as follows:
+ 1. For the first vector mask argument, use v0 to pass it.
+ 2. For vector data arguments or rest vector mask arguments, starting
+ from the v8 register, if a vector register group between v8-v23 that has
+ not been allocated can be found and the first register number is a
+ multiple of LMUL, then allocate this vector register group to the argument
+ and mark these registers as allocated. Otherwise, pass it by reference and
+ are replaced in the 12 argument list with the address.
+ 3. For tuple vector data arguments, starting from the v8 register, if
+ NFIELDS consecutive vector register groups between v8-v23 that have not
+ been allocated can be found and the first register number is a multiple of
+ LMUL, then allocate these vector register groups to the argument and mark
+ these registers as allocated. Otherwise, pass it by reference and are
+ replaced in the argument list with the address
+ */
+};
+
/* Arguments can be passed as on stack arguments, or by reference. The
on stack arguments must be in a continuous region starting from $sp,
while the by reference arguments can be anywhere, but we'll put them
@@ -2749,10 +2937,16 @@ struct riscv_call_info
{
riscv_call_info (struct gdbarch *gdbarch)
: int_regs (RISCV_A0_REGNUM, RISCV_A0_REGNUM + 7),
- float_regs (RISCV_FA0_REGNUM, RISCV_FA0_REGNUM + 7)
+ float_regs (RISCV_FA0_REGNUM, RISCV_FA0_REGNUM + 7),
+ vector_regs (RISCV_V0_REGNUM + 8, RISCV_V0_REGNUM + 23)
{
xlen = riscv_abi_xlen (gdbarch);
flen = riscv_abi_flen (gdbarch);
+ /* According to the RVV specification, a binary file does not require
+ any particular vlenb value. However, a target vlenb value is
+ required to place arguments correctly. For this purpose, we save
+ the riscv_isa_vlenb value here. */
+ vlenb = riscv_isa_vlenb (gdbarch);
/* Reduce the number of integer argument registers when using the
embedded abi (i.e. rv32e). */
@@ -2762,6 +2956,10 @@ struct riscv_call_info
/* Disable use of floating point registers if needed. */
if (!riscv_has_fp_abi (gdbarch))
float_regs.next_regnum = float_regs.last_regnum + 1;
+
+ /* Disable use of vector registers if needed. */
+ if (!riscv_has_vector_abi (gdbarch))
+ vector_regs.available_intervals.clear ();
}
/* Track the memory areas used for holding in-memory arguments to a
@@ -2776,10 +2974,15 @@ struct riscv_call_info
passing an argument. */
struct riscv_arg_reg float_regs;
+ /* Holds information about the next vector register to use for
+ passing an argument. */
+ struct riscv_vector_arg_reg vector_regs;
+
/* The XLEN and FLEN are copied in to this structure for convenience, and
are just the results of calling RISCV_ABI_XLEN and RISCV_ABI_FLEN. */
int xlen;
int flen;
+ int vlenb;
};
/* Return the number of registers available for use as parameters in the
@@ -2821,6 +3024,410 @@ riscv_assign_reg_location (struct riscv_arg_info::location *loc,
return false;
}
+struct rvv_type_info
+{
+ /* Selected Element Width. For RVV_BOOL types, this field holds EEW/EMUL
+ value, encoded into the type. */
+ enum class rvv_sew_t : int
+ {
+ SEW8 = 8,
+ SEW16 = 16,
+ SEW32 = 32,
+ SEW64 = 64,
+ SEW_UNKNOWN,
+ } sew = rvv_sew_t::SEW_UNKNOWN;
+
+ /* Length Multiplier, amount of registers used for this type. */
+ enum class rvv_lmul_t : int
+ {
+ LMUL1 = 1,
+ LMUL2 = 2,
+ LMUL4 = 4,
+ LMUL8 = 8,
+ LMUL_UNKNOWN,
+ } lmul = rvv_lmul_t::LMUL_UNKNOWN;
+
+ /* For non-tuple types, nfield = 1. */
+ enum class rvv_nfield_t : int
+ {
+ NFIELD1 = 1,
+ NFIELD2,
+ NFIELD3,
+ NFIELD4,
+ NFIELD5,
+ NFIELD6,
+ NFIELD7,
+ NFIELD8,
+ NFIELD_UNKNOWN,
+ } nfield = rvv_nfield_t::NFIELD_UNKNOWN;
+
+ enum class rvv_elem_t : char
+ {
+ RVV_INT,
+ RVV_UINT,
+ RVV_FLOAT,
+ RVV_BOOL,
+ RVV_UNKNOWN,
+ } element_type = rvv_elem_t::RVV_UNKNOWN;
+
+ /* is_fractional_lmul means, that used only part of a vector
+ register. For example, if lmul = 2 and is_fractional_lmul =
+ true it means that used a half of a register. */
+ bool is_fractional_lmul = false;
+};
+
+struct rvv_type_name_mapping_t
+{
+ const char *name;
+ rvv_type_info::rvv_elem_t type;
+};
+
+static constexpr std::array<rvv_type_name_mapping_t, 4> rvv_type_names = {
+ rvv_type_name_mapping_t { "int", rvv_type_info::rvv_elem_t::RVV_INT },
+ rvv_type_name_mapping_t { "uint", rvv_type_info::rvv_elem_t::RVV_UINT },
+ rvv_type_name_mapping_t { "float", rvv_type_info::rvv_elem_t::RVV_FLOAT },
+ rvv_type_name_mapping_t { "bool", rvv_type_info::rvv_elem_t::RVV_BOOL }
+};
+
+static bool
+supported_fractional_sew_lmul (rvv_type_info::rvv_lmul_t lmul,
+ rvv_type_info::rvv_sew_t sew)
+{
+ gdb_assert (lmul != rvv_type_info::rvv_lmul_t::LMUL_UNKNOWN);
+ gdb_assert (sew != rvv_type_info::rvv_sew_t::SEW_UNKNOWN);
+ /* More info in RISC-V C Intrinsic Specification Type
+ * System 7.1, 7.2, 7.3, 7.4. */
+ return static_cast<int> (lmul) * static_cast<int> (sew) <= 64;
+}
+
+/* verify_rvv_type() verify RVV types according to specification. */
+static bool
+verify_rvv_type (const rvv_type_info &type_info)
+{
+ if (type_info.lmul == rvv_type_info::rvv_lmul_t::LMUL1
+ && type_info.is_fractional_lmul)
+ return false;
+
+ /* Restriction from RISC-V Vector Specification: LMUL * NFIELDS <= 8. */
+ if (!type_info.is_fractional_lmul
+ && (static_cast<int> (type_info.lmul)
+ * static_cast<int> (type_info.nfield)
+ > 8))
+ return false;
+
+ switch (type_info.element_type)
+ {
+ case rvv_type_info::rvv_elem_t::RVV_FLOAT:
+ /* For float types at least SEW16 is required. */
+ if (type_info.sew != rvv_type_info::rvv_sew_t::SEW16
+ && type_info.sew != rvv_type_info::rvv_sew_t::SEW32
+ && type_info.sew != rvv_type_info::rvv_sew_t::SEW64)
+ return false;
+
+ /* For float types at least LMUL = 1/4 is required. */
+ if (type_info.lmul == rvv_type_info::rvv_lmul_t::LMUL8
+ && type_info.is_fractional_lmul)
+ return false;
+
+ /* rvv_spec_requirement condition applies only to types with fractional
+ LMUL. */
+ if (!type_info.is_fractional_lmul)
+ return true;
+
+ return supported_fractional_sew_lmul (type_info.lmul, type_info.sew);
+
+ case rvv_type_info::rvv_elem_t::RVV_INT:
+ case rvv_type_info::rvv_elem_t::RVV_UINT:
+ /* For int/uint types at least SEW8 is required. */
+ if (type_info.sew != rvv_type_info::rvv_sew_t::SEW8
+ && type_info.sew != rvv_type_info::rvv_sew_t::SEW16
+ && type_info.sew != rvv_type_info::rvv_sew_t::SEW32
+ && type_info.sew != rvv_type_info::rvv_sew_t::SEW64)
+ return false;
+
+ /* rvv_spec_requirement condition applies only to types with fractional
+ LMUL. */
+ if (!type_info.is_fractional_lmul)
+ return true;
+
+ return supported_fractional_sew_lmul (type_info.lmul, type_info.sew);
+
+ case rvv_type_info::rvv_elem_t::RVV_BOOL:
+ /* These restrictions do not follow from the specification, but from the
+ internal constraints of the structure of rvv_type_info. */
+ return (type_info.lmul == rvv_type_info::rvv_lmul_t::LMUL1
+ && type_info.nfield == rvv_type_info::rvv_nfield_t::NFIELD1
+ && !type_info.is_fractional_lmul);
+
+ default:
+ return false;
+ }
+}
+
+static std::regex
+get_rvv_type_regex ()
+{
+ /* According to specification, RVV type names don't start with __rvv_ (like
+ vint64m1_t), but in GCC and Clang they are aliases (__rvv_int64m1_t). */
+ auto pipe_fold = [] (const std::string &a,
+ const rvv_type_name_mapping_t &b) {
+ return a + "|" + std::string (b.name);
+ };
+ std::string accumulator
+ = std::accumulate (std::next (rvv_type_names.begin ()),
+ rvv_type_names.end (),
+ std::string (rvv_type_names[0].name), pipe_fold);
+ return std::regex ("__rvv_(" + accumulator
+ + ")(1|2|4|8|16|32|64)((m|mf)([1248]))?(x([2-8]))?_t");
+}
+
+struct parsed_rvv_type_t
+{
+ enum class group
+ {
+ name = 1,
+ sew,
+ lmul_str,
+ lmul_type,
+ lmul_val,
+ nfield_str,
+ nfield_val
+ };
+
+ static std::optional<parsed_rvv_type_t> parse (std::string_view name)
+ {
+ parsed_rvv_type_t res;
+ if (std::regex_search (name.begin (), name.end (), res.matches,
+ rvv_type_regex))
+ return res;
+ return std::nullopt;
+ }
+
+ std::string_view get (group g) const
+ {
+ long unsigned index = static_cast<long unsigned> (g);
+ const auto &sm = matches[index];
+ return std::string_view (sm.first, sm.length ());
+ }
+
+private:
+ parsed_rvv_type_t () = default;
+ std::cmatch matches;
+ inline static const std::regex rvv_type_regex = get_rvv_type_regex ();
+};
+
+static std::optional<rvv_type_info>
+get_rvv_type_info_unverified (struct type *type)
+{
+ if (!type)
+ return std::nullopt;
+
+ type = check_typedef (type);
+
+ if (!type->name ())
+ {
+ riscv_infcall_debug_printf (
+ "The type name is missing, unable to get RVV type info.");
+ return std::nullopt;
+ }
+
+ if (type->code () != TYPE_CODE_ARRAY && type->code () != TYPE_CODE_STRUCT)
+ {
+ riscv_infcall_debug_printf ("Incorrect type_code: %d. Expected %d "
+ "(TYPE_CODE_ARRAY) or %d (TYPE_CODE_STRUCT)",
+ type->code (), TYPE_CODE_ARRAY,
+ TYPE_CODE_STRUCT);
+ return std::nullopt;
+ }
+
+ auto parsed_rvv_type_holder = parsed_rvv_type_t::parse (type->name ());
+ if (!parsed_rvv_type_holder.has_value ())
+ {
+ riscv_infcall_debug_printf ("Failed to match RVV type name: %s",
+ type->name ());
+ return std::nullopt;
+ }
+ parsed_rvv_type_t parsed_rvv_type = parsed_rvv_type_holder.value ();
+ rvv_type_info res;
+
+ auto it = std::find_if (
+ rvv_type_names.begin (), rvv_type_names.end (),
+ [parsed_rvv_type] (const rvv_type_name_mapping_t &type_name) {
+ return parsed_rvv_type.get (parsed_rvv_type_t::group::name)
+ .compare (type_name.name)
+ == 0;
+ });
+ if (it == rvv_type_names.end ())
+ {
+ riscv_infcall_debug_printf (
+ "Unable to find RVV element type in type name %s.", type->name ());
+ return std::nullopt;
+ }
+ res.element_type = it->type;
+
+ if (auto sew_val = parse_integer<unsigned> (
+ parsed_rvv_type.get (parsed_rvv_type_t::group::sew)))
+ {
+ res.sew = static_cast<rvv_type_info::rvv_sew_t> (sew_val.value ());
+ }
+ else
+ {
+ std::string_view sew_str
+ = parsed_rvv_type.get (parsed_rvv_type_t::group::sew);
+ riscv_infcall_debug_printf (
+ "Failed to convert SEW string (%.*s) to unsigned",
+ static_cast<int> (sew_str.size ()), sew_str.data ());
+ return std::nullopt;
+ }
+
+ if (!parsed_rvv_type.get (parsed_rvv_type_t::group::lmul_str).empty ())
+ {
+ if (parsed_rvv_type.get (parsed_rvv_type_t::group::lmul_type)
+ .compare ("mf")
+ == 0)
+ res.is_fractional_lmul = true;
+ else
+ res.is_fractional_lmul = false;
+
+ if (auto lmul_val = parse_integer<unsigned> (
+ parsed_rvv_type.get (parsed_rvv_type_t::group::lmul_val)))
+ {
+ res.lmul
+ = static_cast<rvv_type_info::rvv_lmul_t> (lmul_val.value ());
+ }
+ else
+ {
+ std::string_view lmul_str
+ = parsed_rvv_type.get (parsed_rvv_type_t::group::lmul_val);
+ riscv_infcall_debug_printf (
+ "Failed to convert LMUL string (%.*s) to unsigned",
+ static_cast<int> (lmul_str.size ()), lmul_str.data ());
+ return std::nullopt;
+ }
+ }
+ else
+ {
+ res.lmul = rvv_type_info::rvv_lmul_t::LMUL1;
+ res.is_fractional_lmul = false;
+ }
+
+ if (!parsed_rvv_type.get (parsed_rvv_type_t::group::nfield_str).empty ())
+ {
+ if (auto nfield_val = parse_integer<unsigned> (
+ parsed_rvv_type.get (parsed_rvv_type_t::group::nfield_val)))
+ {
+ res.nfield
+ = static_cast<rvv_type_info::rvv_nfield_t> (nfield_val.value ());
+ }
+ else
+ {
+ std::string_view nfield_str
+ = parsed_rvv_type.get (parsed_rvv_type_t::group::nfield_val);
+ riscv_infcall_debug_printf (
+ "Failed to convert NFIELD string (%.*s) to unsigned",
+ static_cast<int> (nfield_str.size ()), nfield_str.data ());
+ return std::nullopt;
+ }
+ }
+ else
+ res.nfield = rvv_type_info::rvv_nfield_t::NFIELD1;
+
+ return res;
+}
+
+static std::optional<rvv_type_info>
+get_rvv_type_info (struct type *type)
+{
+ std::optional<rvv_type_info> res = get_rvv_type_info_unverified (type);
+
+ if (res.has_value () && verify_rvv_type (res.value ()))
+ return res;
+
+ return std::nullopt;
+}
+
+static bool
+is_rvv_type (struct type *type)
+{
+ return get_rvv_type_info (type).has_value ();
+}
+
+static bool
+riscv_assign_vec_reg_location (struct riscv_arg_info *ainfo,
+ struct riscv_vector_arg_reg *reg,
+ struct type *func_arg_type, int vlenb)
+{
+ int data_length = vlenb; /* Amount of data that is stored on one register */
+
+ struct riscv_arg_info::location *loc0 = &ainfo->argloc[0];
+ struct riscv_arg_info::location *loc1 = &ainfo->argloc[1];
+
+ rvv_type_info arg_type_info;
+ if (std::optional<rvv_type_info> res = get_rvv_type_info (func_arg_type))
+ arg_type_info = res.value ();
+ else
+ gdb_assert_not_reached ("Incorrect type %s", func_arg_type->name ());
+
+ riscv_infcall_debug_printf (
+ "rvv_type_info of %s: element_type = %d, sew = %u, lmul = %u (%s "
+ "fractional), nfield = %u",
+ func_arg_type->name (), static_cast<int> (arg_type_info.element_type),
+ static_cast<int> (arg_type_info.sew),
+ static_cast<int> (arg_type_info.lmul),
+ (arg_type_info.is_fractional_lmul ? "is" : "is not"),
+ static_cast<int> (arg_type_info.nfield));
+
+ int num_required_regs = ((arg_type_info.is_fractional_lmul)
+ ? 1
+ : static_cast<int> (arg_type_info.lmul))
+ * static_cast<int> (arg_type_info.nfield);
+
+ if (arg_type_info.is_fractional_lmul)
+ {
+ num_required_regs = static_cast<int> (arg_type_info.nfield);
+ data_length = data_length / static_cast<int> (arg_type_info.lmul);
+ }
+
+ int first_regnum = -1;
+
+ /* Representation of vector segmented types, like vint32m4x2_t,
+ is different in Clang and GCC.
+ In Clang, all types are arrays.
+ In GCC, segmented types are struct's, other vector types are arrays. */
+ if (ainfo->type->code () == TYPE_CODE_ARRAY)
+ {
+ if (ainfo->type->target_type ()->code () == TYPE_CODE_BOOL)
+ first_regnum = reg->try_use_v0 ();
+ else
+ first_regnum
+ = reg->get_interval_start (num_required_regs,
+ static_cast<int> (arg_type_info.nfield));
+ }
+ else if (ainfo->type->code () == TYPE_CODE_STRUCT)
+ {
+ first_regnum
+ = reg->get_interval_start (num_required_regs,
+ static_cast<int> (arg_type_info.nfield));
+ }
+
+ if (first_regnum == -1)
+ return false;
+
+ int last_regnum = first_regnum + num_required_regs - 1;
+
+ loc0->loc_type = riscv_arg_info::location::in_several_regs;
+ loc0->loc_data.regno = first_regnum;
+ loc0->c_length = data_length;
+ loc0->c_offset = 0;
+
+ loc1->loc_type = riscv_arg_info::location::in_several_regs;
+ loc1->loc_data.regno = last_regnum;
+ loc1->c_length = 0;
+ loc1->c_offset = 0;
+
+ return true;
+}
+
/* Assign LOC a location as the next stack parameter, and update MEMORY to
record that an area of stack has been used to hold the parameter
described by LOC.
@@ -3229,21 +3836,44 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo,
riscv_call_arg_scalar_int (ainfo, cinfo);
}
+static void
+riscv_call_arg_vector (struct riscv_arg_info *ainfo,
+ struct riscv_call_info *cinfo,
+ struct type *func_arg_type)
+{
+ if (!riscv_assign_vec_reg_location (ainfo, &cinfo->vector_regs,
+ func_arg_type, cinfo->vlenb))
+ {
+ // Try to pass value by reference
+ ainfo->argloc[0].loc_type = riscv_arg_info::location::by_ref;
+ cinfo->memory.ref_offset = align_up (cinfo->memory.ref_offset,
+ ainfo->align);
+ ainfo->argloc[0].loc_data.offset = cinfo->memory.ref_offset;
+ cinfo->memory.ref_offset += ainfo->length;
+ ainfo->argloc[0].c_length = ainfo->length;
+
+ if (!riscv_assign_reg_location (&ainfo->argloc[1], &cinfo->int_regs,
+ cinfo->xlen, 0))
+ riscv_assign_stack_location (&ainfo->argloc[1], &cinfo->memory,
+ cinfo->xlen, cinfo->xlen);
+ }
+}
+
/* Assign a location to call (or return) argument AINFO, the location is
selected from CINFO which holds information about what call argument
locations are available for use next. The TYPE is the type of the
argument being passed, this information is recorded into AINFO (along
with some additional information derived from the type). IS_UNNAMED
is true if this is an unnamed (stdarg) argument, this info is also
- recorded into AINFO.
+ recorded into AINFO. FUNC_ARG_TYPE is the type of the function parameter in
+ its declaration.
After assigning a location to AINFO, CINFO will have been updated. */
static void
-riscv_arg_location (struct gdbarch *gdbarch,
- struct riscv_arg_info *ainfo,
- struct riscv_call_info *cinfo,
- struct type *type, bool is_unnamed)
+riscv_arg_location (struct gdbarch *gdbarch, struct riscv_arg_info *ainfo,
+ struct riscv_call_info *cinfo, struct type *type,
+ struct type *func_arg_type, bool is_unnamed)
{
ainfo->type = type;
ainfo->length = ainfo->type->length ();
@@ -3253,6 +3883,12 @@ riscv_arg_location (struct gdbarch *gdbarch,
ainfo->argloc[0].c_length = 0;
ainfo->argloc[1].c_length = 0;
+ if (is_rvv_type (func_arg_type)) /* for RISC_V vector registers */
+ {
+ riscv_call_arg_vector (ainfo, cinfo, func_arg_type);
+ return;
+ }
+
switch (ainfo->type->code ())
{
case TYPE_CODE_INT:
@@ -3375,6 +4011,14 @@ riscv_print_arg_location (ui_file *stream, struct gdbarch *gdbarch,
}
break;
+ case riscv_arg_info::location::in_several_regs:
+ gdb_printf (stream, ", registers from %s to %s",
+ gdbarch_register_name (gdbarch,
+ info->argloc[0].loc_data.regno),
+ gdbarch_register_name (gdbarch,
+ info->argloc[1].loc_data.regno));
+ break;
+
default:
gdb_assert_not_reached ("unknown argument location type");
}
@@ -3389,15 +4033,13 @@ static void
riscv_regcache_cooked_write (int regnum, const gdb_byte *data, int len,
struct regcache *regcache, int flen)
{
- gdb_byte tmp [sizeof (ULONGEST)];
-
+ int regsize = register_size (regcache->arch (), regnum);
+ std::vector<gdb_byte> tmp (regsize);
/* FP values in FP registers must be NaN-boxed. */
if (riscv_is_fp_regno_p (regnum) && len < flen)
- memset (tmp, -1, sizeof (tmp));
- else
- memset (tmp, 0, sizeof (tmp));
- memcpy (tmp, data, len);
- regcache->cooked_write (regnum, tmp);
+ memset (tmp.data (), -1, tmp.size ());
+ memcpy (tmp.data (), data, len);
+ regcache->cooked_write (regnum, tmp.data ());
}
/* Implement the push dummy call gdbarch callback. */
@@ -3437,16 +4079,21 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
{
struct value *arg_value;
struct type *arg_type;
+ struct type *func_arg_type;
struct riscv_arg_info *info = &arg_info[i];
arg_value = args[i];
arg_type = check_typedef (arg_value->type ());
- riscv_arg_location (gdbarch, info, &call_info, arg_type,
+ func_arg_type = (i < ftype->num_fields ()) ? ftype->field (i).type ()
+ : nullptr;
+
+ riscv_arg_location (gdbarch, info, &call_info, arg_type, func_arg_type,
ftype->has_varargs () && i >= ftype->num_fields ());
if (info->type != arg_type)
arg_value = value_cast (info->type, arg_value);
+
info->contents = arg_value->contents ().data ();
}
@@ -3458,13 +4105,17 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
{
RISCV_INFCALL_SCOPED_DEBUG_START_END ("dummy call args");
riscv_infcall_debug_printf ("floating point ABI %s in use",
- (riscv_has_fp_abi (gdbarch)
- ? "is" : "is not"));
+ (riscv_has_fp_abi (gdbarch) ? "is"
+ : "is not"));
+ riscv_infcall_debug_printf ("vector ABI %s in use",
+ (riscv_has_vector_abi (gdbarch) ? "is"
+ : "is not"));
riscv_infcall_debug_printf ("xlen: %d", call_info.xlen);
riscv_infcall_debug_printf ("flen: %d", call_info.flen);
+ riscv_infcall_debug_printf ("vlenb: %d", call_info.vlenb);
if (return_method == return_method_struct)
- riscv_infcall_debug_printf
- ("[**] struct return pointer in register $A0");
+ riscv_infcall_debug_printf (
+ "[**] struct return pointer in register $A0");
for (i = 0; i < nargs; ++i)
{
struct riscv_arg_info *info = &arg_info [i];
@@ -3538,6 +4189,22 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
second_arg_data = (gdb_byte *) &dst;
break;
+ case riscv_arg_info::location::in_several_regs:
+ {
+ const gdb_byte *cur_contents = info->contents;
+ int cur_c_length = info->argloc[0].c_length;
+ for (int cur_regno = info->argloc[0].loc_data.regno;
+ cur_regno <= info->argloc[1].loc_data.regno; cur_regno++)
+ {
+ riscv_regcache_cooked_write (cur_regno, cur_contents,
+ cur_c_length, regcache,
+ call_info.flen);
+ cur_contents += cur_c_length;
+ }
+ second_arg_length = 0;
+ }
+ break;
+
default:
gdb_assert_not_reached ("unknown argument location type");
}
@@ -3568,6 +4235,8 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
}
case riscv_arg_info::location::by_ref:
+ case riscv_arg_info::location::
+ in_several_regs: /* We shouldn't get here for this case*/
default:
/* The second location should never be a reference, any
argument being passed by reference just places its address
@@ -3606,9 +4275,14 @@ riscv_return_value (struct gdbarch *gdbarch,
struct riscv_call_info call_info (gdbarch);
struct riscv_arg_info info;
struct type *arg_type;
+ struct type *func_retval_type;
arg_type = check_typedef (type);
- riscv_arg_location (gdbarch, &info, &call_info, arg_type, false);
+ func_retval_type = (function && function->type ())
+ ? function->type ()->target_type ()
+ : nullptr;
+ riscv_arg_location (gdbarch, &info, &call_info, arg_type, func_retval_type,
+ false);
if (riscv_debug_infcall)
{
@@ -3761,6 +4435,38 @@ riscv_return_value (struct gdbarch *gdbarch,
}
break;
+ case riscv_arg_info::location::in_several_regs:
+ {
+ int first_regnum = info.argloc[0].loc_data.regno;
+ int last_regnum = info.argloc[1].loc_data.regno;
+
+ gdb_byte *tmp_readbuf = readbuf;
+ const gdb_byte *tmp_writebuf = writebuf;
+
+ for (int cur_regnum = first_regnum; cur_regnum <= last_regnum;
+ cur_regnum++)
+ {
+ if (readbuf)
+ {
+ gdb_byte *ptr = tmp_readbuf + info.argloc[0].c_offset;
+ regcache->cooked_read_part (cur_regnum, 0,
+ info.argloc[0].c_length, ptr);
+ tmp_readbuf += info.argloc[0].c_length;
+ }
+
+ if (writebuf)
+ {
+ const gdb_byte *ptr = tmp_writebuf
+ + info.argloc[0].c_offset;
+ riscv_regcache_cooked_write (cur_regnum, ptr,
+ info.argloc[0].c_length,
+ regcache, call_info.flen);
+ tmp_writebuf += info.argloc[0].c_length;
+ }
+ }
+ }
+ break;
+
case riscv_arg_info::location::on_stack:
default:
error (_("invalid argument location"));
@@ -3795,6 +4501,7 @@ riscv_return_value (struct gdbarch *gdbarch,
switch (info.argloc[0].loc_type)
{
case riscv_arg_info::location::in_reg:
+ case riscv_arg_info::location::in_several_regs:
return RETURN_VALUE_REGISTER_CONVENTION;
case riscv_arg_info::location::by_ref:
return RETURN_VALUE_ABI_PRESERVES_ADDRESS;
@@ -3923,6 +4630,17 @@ static const struct frame_unwind_legacy riscv_frame_unwind (
/*.prev_arch =*/ NULL
);
+static bool
+riscv_search_extension_in_march (std::string_view march,
+ std::string_view extension)
+{
+ std::string regex_string = "_" + std::string (extension)
+ + "(_|$|[1-9]?\\d+p[1-9]?\\d)";
+ std::regex regexp_for_extension (regex_string);
+ return std::regex_search (march.begin (), march.end (),
+ regexp_for_extension);
+}
+
/* Extract a set of required target features out of ABFD. If ABFD is
nullptr then a RISCV_GDBARCH_FEATURES is returned in its default state. */
@@ -3963,6 +4681,31 @@ riscv_features_from_bfd (const bfd *abfd)
}
features.embedded = true;
}
+
+ obj_attribute *obj_attr = elf_known_obj_attributes_proc (abfd);
+ const char *march = obj_attr[Tag_RISCV_arch].s;
+ if (march)
+ {
+ /* According to the RVV specification, a binary file does not require
+ any particular vlenb value. Therefore, we used minimal vlenb value
+ to indicate that the vector ABI is in use. Additionally, a valid
+ vlenb value is required here, as it will be used later to create a
+ default target description. */
+ std::string_view march_str (march);
+ if (riscv_search_extension_in_march (march_str, "v"))
+ features.vlenb = 16;
+ else if (riscv_search_extension_in_march (march_str, "zve64x")
+ || riscv_search_extension_in_march (march_str, "zve64f")
+ || riscv_search_extension_in_march (march_str, "zve64d"))
+ features.vlenb = 8;
+ else if (riscv_search_extension_in_march (march_str, "zve32x")
+ || riscv_search_extension_in_march (march_str, "zve32f"))
+ features.vlenb = 4;
+ else
+ features.vlenb = 0;
+ }
+ else
+ features.vlenb = 0;
}
return features;
@@ -4265,6 +5008,13 @@ riscv_gdbarch_init (struct gdbarch_info info,
error (_("bfd requires flen %d, but target has flen %d"),
abi_features.flen, features.flen);
+ /* Look at riscv_features_from_bfd*/
+ if ((abi_features.vlenb > 0) && (features.vlenb == 0))
+ {
+ warning (_ ("bfd requires non-zero vlenb, but target has vlenb = 0, "
+ "vector registers unsupported"));
+ }
+
/* Find a candidate among the list of pre-declared architectures. */
for (arches = gdbarch_list_lookup_by_info (arches, &info);
arches != NULL;
@@ -5468,3 +6218,13 @@ riscv_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
return 0;
}
+
+bool
+riscv_is_vpr_or_vcsr (unsigned regnum)
+{
+ return (regnum >= RISCV_V0_REGNUM && regnum <= RISCV_V0_REGNUM + 31)
+ || regnum == RISCV_CSR_VSTART_REGNUM
+ || regnum == RISCV_CSR_VCSR_REGNUM || regnum == RISCV_CSR_VL_REGNUM
+ || regnum == RISCV_CSR_VTYPE_REGNUM
+ || regnum == RISCV_CSR_VLENB_REGNUM;
+}
diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
index 344a995a680..a6fd89c9646 100644
--- a/gdb/riscv-tdep.h
+++ b/gdb/riscv-tdep.h
@@ -23,61 +23,7 @@
#include "arch/riscv.h"
#include "gdbarch.h"
-
-/* RiscV register numbers. */
-enum
-{
- RISCV_ZERO_REGNUM = 0, /* Read-only register, always 0. */
- RISCV_RA_REGNUM = 1, /* Return Address. */
- RISCV_SP_REGNUM = 2, /* Stack Pointer. */
- RISCV_GP_REGNUM = 3, /* Global Pointer. */
- RISCV_TP_REGNUM = 4, /* Thread Pointer. */
- RISCV_FP_REGNUM = 8, /* Frame Pointer. */
- RISCV_A0_REGNUM = 10, /* First argument. */
- RISCV_A1_REGNUM = 11, /* Second argument. */
- RISCV_A2_REGNUM = 12, /* Third argument. */
- RISCV_A3_REGNUM = 13, /* Forth argument. */
- RISCV_A4_REGNUM = 14, /* Fifth argument. */
- RISCV_A5_REGNUM = 15, /* Sixth argument. */
- RISCV_A7_REGNUM = 17, /* Register to pass syscall number. */
- RISCV_PC_REGNUM = 32, /* Program Counter. */
-
- RISCV_NUM_INTEGER_REGS = 32,
-
- RISCV_FIRST_FP_REGNUM = 33, /* First Floating Point Register */
- RISCV_FA0_REGNUM = 43,
- RISCV_FA1_REGNUM = RISCV_FA0_REGNUM + 1,
- RISCV_LAST_FP_REGNUM = 64, /* Last Floating Point Register */
-
- RISCV_FIRST_CSR_REGNUM = 65, /* First CSR */
-#define DECLARE_CSR(name, num, class, define_version, abort_version) \
- RISCV_ ## num ## _REGNUM = RISCV_FIRST_CSR_REGNUM + num,
-#include "opcode/riscv-opc.h"
-#undef DECLARE_CSR
- RISCV_LAST_CSR_REGNUM = 4160,
- RISCV_CSR_LEGACY_MISA_REGNUM = 0xf10 + RISCV_FIRST_CSR_REGNUM,
-
- RISCV_PRIV_REGNUM = 4161,
-
- RISCV_V0_REGNUM,
-
- RISCV_V31_REGNUM = RISCV_V0_REGNUM + 31,
-
- RISCV_LAST_REGNUM = RISCV_V31_REGNUM
-};
-
-/* RiscV DWARF register numbers. */
-enum
-{
- RISCV_DWARF_REGNUM_X0 = 0,
- RISCV_DWARF_REGNUM_X31 = 31,
- RISCV_DWARF_REGNUM_F0 = 32,
- RISCV_DWARF_REGNUM_F31 = 63,
- RISCV_DWARF_REGNUM_V0 = 96,
- RISCV_DWARF_REGNUM_V31 = 127,
- RISCV_DWARF_FIRST_CSR = 4096,
- RISCV_DWARF_LAST_CSR = 8191,
-};
+#include "riscv-regs.h"
/* RISC-V specific per-architecture information. */
struct riscv_gdbarch_tdep : gdbarch_tdep_base
@@ -135,6 +81,8 @@ extern int riscv_isa_xlen (struct gdbarch *gdbarch);
single, double or quad floating point support is available. */
extern int riscv_isa_flen (struct gdbarch *gdbarch);
+extern int riscv_isa_vlenb (struct gdbarch *gdbarch);
+
/* Return the width in bytes of the general purpose register abi for
GDBARCH. This can be equal to, or less than RISCV_ISA_XLEN and reflects
how the binary was compiled rather than the hardware that is available.
@@ -158,6 +106,8 @@ extern int riscv_abi_flen (struct gdbarch *gdbarch);
argument registers. */
extern bool riscv_abi_embedded (struct gdbarch *gdbarch);
+extern int riscv_abi_vlenb (struct gdbarch *gdbarch);
+
/* Single step based on where the current instruction will take us. */
extern std::vector<CORE_ADDR> riscv_software_single_step
(struct regcache *regcache);
@@ -194,4 +144,7 @@ extern int riscv_process_record (struct gdbarch *gdbarch,
/* The names of the RISC-V target description features. */
extern const char *riscv_feature_name_csr;
+/* Determines if regnum corresponds to vector register vX or vector CSR. */
+extern bool riscv_is_vpr_or_vcsr (unsigned regnum);
+
#endif /* GDB_RISCV_TDEP_H */
diff --git a/gdbserver/linux-riscv-low.cc b/gdbserver/linux-riscv-low.cc
index 8cc0a980fc1..4f26c3f6189 100644
--- a/gdbserver/linux-riscv-low.cc
+++ b/gdbserver/linux-riscv-low.cc
@@ -21,6 +21,7 @@
#include "linux-low.h"
#include "tdesc.h"
#include "elf/common.h"
+#include "nat/riscv-linux-ptrace.h"
#include "nat/riscv-linux-tdesc.h"
#include "opcode/riscv.h"
@@ -102,26 +103,6 @@ riscv_target::low_get_syscall_trapinfo (regcache *regcache, int *sysno)
*sysno = (int)l_sysno;
}
-/* Implementation of linux target ops method "low_arch_setup". */
-
-void
-riscv_target::low_arch_setup ()
-{
- static const char *expedite_regs[] = { "sp", "pc", NULL };
-
- const riscv_gdbarch_features features
- = riscv_linux_read_features (current_thread->id.lwp ());
- target_desc_up tdesc = riscv_create_target_description (features);
-
- if (tdesc->expedite_regs.empty ())
- {
- init_target_desc (tdesc.get (), expedite_regs, GDB_OSABI_LINUX);
- gdb_assert (!tdesc->expedite_regs.empty ());
- }
-
- current_process ()->tdesc = tdesc.release ();
-}
-
/* Collect GPRs from REGCACHE into BUF. */
static void
@@ -185,23 +166,74 @@ riscv_store_fpregset (struct regcache *regcache, const void *buf)
supply_register_by_name (regcache, "fcsr", regbuf);
}
+/* Collect vector regs from REGCACHE into BUF. */
+
+static void
+riscv_fill_vecregset (struct regcache *regcache, void *buf)
+{
+ const struct target_desc *tdesc = regcache->tdesc;
+
+ struct __riscv_v_regset_state *vecregs
+ = (struct __riscv_v_regset_state *) buf;
+ unsigned long vlenb = vecregs->vlenb;
+ gdb_assert (vlenb > 0);
+ int v0_regno = find_regno (tdesc, "v0");
+ gdb_byte *regbuf = (gdb_byte *) vecregs->vreg;
+
+ for (int i = 0; i < 32; i++, regbuf += vlenb)
+ collect_register (regcache, v0_regno + i, regbuf);
+
+ collect_register_by_name (regcache, "vstart", &vecregs->vstart);
+ collect_register_by_name (regcache, "vcsr", &vecregs->vcsr);
+ collect_register_by_name (regcache, "vl", &vecregs->vl);
+ collect_register_by_name (regcache, "vtype", &vecregs->vtype);
+ collect_register_by_name (regcache, "vlenb", &vecregs->vlenb);
+}
+
+/* Supply vector regs from BUF into REGCACHE. */
+
+static void
+riscv_store_vecregset (struct regcache *regcache, const void *buf)
+{
+ const struct target_desc *tdesc = regcache->tdesc;
+
+ const struct __riscv_v_regset_state *vecregs
+ = (const struct __riscv_v_regset_state *) buf;
+ unsigned long vlenb = vecregs->vlenb;
+ gdb_assert (vlenb > 0);
+ int v0_regno = find_regno (tdesc, "v0");
+ int v0_regsize = register_size (tdesc, v0_regno);
+ gdb_assert (vlenb == v0_regsize);
+ const gdb_byte *regbuf = (const gdb_byte *) vecregs->vreg;
+
+ for (int i = 0; i < 32; i++, regbuf += vlenb)
+ supply_register (regcache, v0_regno + i, regbuf);
+
+ supply_register_by_name (regcache, "vstart", &vecregs->vstart);
+ supply_register_by_name (regcache, "vcsr", &vecregs->vcsr);
+ supply_register_by_name (regcache, "vl", &vecregs->vl);
+ supply_register_by_name (regcache, "vtype", &vecregs->vtype);
+ supply_register_by_name (regcache, "vlenb", &vecregs->vlenb);
+}
+
/* RISC-V/Linux regsets. FPRs are optional and come in different sizes,
so define multiple regsets for them marking them all as OPTIONAL_REGS
rather than FP_REGS, so that "regsets_fetch_inferior_registers" picks
the right one according to size. */
static struct regset_info riscv_regsets[] = {
- { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS,
- sizeof (elf_gregset_t), GENERAL_REGS,
- riscv_fill_gregset, riscv_store_gregset },
+ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, sizeof (elf_gregset_t),
+ GENERAL_REGS, riscv_fill_gregset, riscv_store_gregset },
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET,
- sizeof (struct __riscv_mc_q_ext_state), OPTIONAL_REGS,
- riscv_fill_fpregset, riscv_store_fpregset },
+ sizeof (struct __riscv_mc_q_ext_state), OPTIONAL_REGS, riscv_fill_fpregset,
+ riscv_store_fpregset },
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET,
- sizeof (struct __riscv_mc_d_ext_state), OPTIONAL_REGS,
- riscv_fill_fpregset, riscv_store_fpregset },
+ sizeof (struct __riscv_mc_d_ext_state), OPTIONAL_REGS, riscv_fill_fpregset,
+ riscv_store_fpregset },
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET,
- sizeof (struct __riscv_mc_f_ext_state), OPTIONAL_REGS,
- riscv_fill_fpregset, riscv_store_fpregset },
+ sizeof (struct __riscv_mc_f_ext_state), OPTIONAL_REGS, riscv_fill_fpregset,
+ riscv_store_fpregset },
+ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_RISCV_VECTOR, 0, EXTENDED_REGS,
+ riscv_fill_vecregset, riscv_store_vecregset },
NULL_REGSET
};
@@ -229,6 +261,45 @@ riscv_target::get_regs_info ()
return &riscv_regs;
}
+/* Setup Vector Regset. */
+static void
+setup_vector_regset (struct regset_info *vector_regset_info,
+ const riscv_gdbarch_features *features)
+{
+ vector_regset_info->size
+ = (features->vlenb
+ ? sizeof (struct __riscv_v_regset_state) + 32 * features->vlenb
+ : 0);
+}
+
+/* Implementation of linux target ops method "low_arch_setup". */
+
+void
+riscv_target::low_arch_setup ()
+{
+ static const char *expedite_regs[] = { "sp", "pc", NULL };
+
+ const riscv_gdbarch_features features
+ = riscv_linux_read_features (current_thread->id.lwp ());
+ target_desc_up tdesc = riscv_create_target_description (features);
+
+ struct regset_info *regset;
+ for (regset = riscv_regsets; regset->size >= 0; regset++)
+ if (regset->nt_type == NT_RISCV_VECTOR)
+ {
+ setup_vector_regset (regset, &features);
+ break;
+ }
+
+ if (tdesc->expedite_regs.empty ())
+ {
+ init_target_desc (tdesc.get (), expedite_regs, GDB_OSABI_LINUX);
+ gdb_assert (!tdesc->expedite_regs.empty ());
+ }
+
+ current_process ()->tdesc = tdesc.release ();
+}
+
/* Implementation of linux target ops method "low_fetch_register". */
bool
diff --git a/gdbsupport/common-utils.h b/gdbsupport/common-utils.h
index de83a715ac4..5f91dbeb3b7 100644
--- a/gdbsupport/common-utils.h
+++ b/gdbsupport/common-utils.h
@@ -20,12 +20,14 @@
#ifndef GDBSUPPORT_COMMON_UTILS_H
#define GDBSUPPORT_COMMON_UTILS_H
+#include <optional>
#include <string>
#include <vector>
#include "gdbsupport/byte-vector.h"
#include "gdbsupport/gdb_unique_ptr.h"
#include "gdbsupport/array-view.h"
#include "poison.h"
+#include <charconv>
#include <string_view>
#if defined HAVE_LIBXXHASH
@@ -279,4 +281,24 @@ struct string_view_hash
} /* namespace gdb */
+/* Parse decimal integer number from string_view. */
+template<typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
+std::optional<T>
+parse_integer (std::string_view str) noexcept
+{
+ if (str.empty ())
+ return std::nullopt;
+
+ T value {};
+ const char *first = str.data ();
+ const char *last = str.data () + str.size ();
+
+ auto [ptr, ec] = std::from_chars (first, last, value, 10);
+
+ if (ec != std::errc {} || ptr != last)
+ return std::nullopt;
+
+ return value;
+}
+
#endif /* GDBSUPPORT_COMMON_UTILS_H */
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 2/3] Reverse execution support for RISC-V Vector Extension
2026-09-25 17:29 [PATCH v2 0/3] RISC-V Vector Extension support Kirill Radkin
2026-09-25 17:29 ` [PATCH v2 1/3] RISC-V Vector Extension Support Kirill Radkin
@ 2026-09-25 17:29 ` Kirill Radkin
2026-09-25 17:29 ` [PATCH v2 3/3] RISC-V Vector Extension Support Testing Kirill Radkin
2 siblings, 0 replies; 4+ messages in thread
From: Kirill Radkin @ 2026-09-25 17:29 UTC (permalink / raw)
To: gdb-patches
Cc: Peter Bergner, Sergey Matyukevich, Jerry Zhang Jian,
Heinrich Schuchardt, Andrew Burgess, Palmer Dabbelt
This patch adds support for reverse execution feature for the RISC-V Vector
Extension (RVV). Implementation was tested on massive auto-generated tests on
Openocd + spike configuration.
---
gdb/riscv-tdep.c | 493 ++++++++++++++++++++++++++++++++++++-
include/opcode/riscv-opc.h | 79 ++++++
include/opcode/riscv.h | 10 +
3 files changed, 580 insertions(+), 2 deletions(-)
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index 12bc51beb38..0cef77f8750 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -5709,6 +5709,18 @@ class riscv_recorded_insn final
return (ival >> OP_SH_CSR) & OP_MASK_CSR;
}
+ /* Helper for decode 32-bit vector instruction VD. */
+ static regnum_type decode_vd (ULONGEST ival) noexcept
+ {
+ return ((ival >> OP_SH_VD) & OP_MASK_VD) + RISCV_V0_REGNUM;
+ }
+
+ /* Helper for decode 32-bit instruction VS2. */
+ static regnum_type decode_vs2 (ULONGEST ival) noexcept
+ {
+ return ((ival >> OP_SH_VS2) & OP_MASK_VS2) + RISCV_V0_REGNUM;
+ }
+
/* Reads register. Returns false if error happened. */
bool
read_reg (regnum_type regnum, ULONGEST &addr) noexcept
@@ -5720,6 +5732,16 @@ class riscv_recorded_insn final
return false;
}
+ bool read_vector_reg (regnum_type regnum, gdb_byte *val) noexcept
+ {
+ gdb_assert (RISCV_V0_REGNUM <= regnum && regnum <= RISCV_V31_REGNUM);
+ if (m_regcache->raw_read (regnum, val) == register_status::REG_VALID)
+ return true;
+
+ warning (_ ("Can not read at vector reg %d"), regnum);
+ return false;
+ }
+
/* Save register. Returns false if error happened. */
bool
save_reg (regnum_type regnum) noexcept
@@ -5827,7 +5849,10 @@ class riscv_recorded_insn final
|| is_xperm4_insn (ival) || is_xperm8_insn (ival)
|| is_zext_h_insn (ival)
|| (m_xlen == 4 && is_zext_h_rv32_insn (ival))
- || (m_xlen == 4 && is_zip_insn (ival)));
+ || (m_xlen == 4 && is_zip_insn (ival))
+ /* vector */
+ || is_vmv_x_s_insn (ival) || is_vcpop_m_insn (ival)
+ || is_vfirst_m_insn (ival));
}
/* Returns true if instruction successfully saved rd. */
@@ -5862,7 +5887,8 @@ class riscv_recorded_insn final
|| is_fmax_d_insn (ival) || is_fcvt_s_d_insn (ival)
|| is_fcvt_d_s_insn (ival) || is_fcvt_d_w_insn (ival)
|| is_fcvt_d_wu_insn (ival) || is_fcvt_d_l_insn (ival)
- || is_fcvt_d_lu_insn (ival) || is_fmv_d_x_insn (ival));
+ || is_fcvt_d_lu_insn (ival) || is_fmv_d_x_insn (ival)
+ || is_vfmv_f_s_insn (ival));
}
/* Returns true if instruction successfully saved floating point rd. */
@@ -5948,6 +5974,454 @@ class riscv_recorded_insn final
&& save_reg (decode_rd (ival)));
}
+ bool decode_width_vector (ULONGEST ival, ULONGEST &width) noexcept
+ {
+ ULONGEST val = (ival >> OP_SH_WIDTH) & OP_MASK_WIDTH;
+
+ switch (val)
+ {
+ case 0x0:
+ width = 8;
+ break;
+ case 0x5:
+ width = 16;
+ break;
+ case 0x6:
+ width = 32;
+ break;
+ case 0x7:
+ width = 64;
+ break;
+ default:
+ warning (_ ("Unexpected vector width value: %lu"), val);
+ return false;
+ }
+
+ return true;
+ }
+
+ bool decode_nfields_vector (ULONGEST ival, ULONGEST &nfields) noexcept
+ {
+ ULONGEST val = (ival >> OP_SH_NF) & OP_MASK_NF;
+
+ if (val >= 8)
+ {
+ warning (_ ("Unexpected nfields value: %lu"), val);
+ return false;
+ }
+
+ nfields = val + 1;
+ return true;
+ }
+
+ bool decode_element_width_vector (ULONGEST val, ULONGEST &elem_width)
+ {
+ ULONGEST sew = (val >> 3) & 0x7;
+ if (sew >= 4)
+ {
+ warning (_ ("Unexpected sew value: %lu"), sew);
+ return false;
+ }
+
+ elem_width = (1 << (sew + 3));
+ return true;
+ }
+
+ /* Applies LMUL, encoded in a vtype value's VLMUL[2:0] field, to the
+ NUMERATOR/DENOMINATOR ratio, returning floor(NUMERATOR / DENOMINATOR
+ * LMUL). VLMUL encodes: 0..3 -> integer LMUL 1,2,4,8; 5..7 ->
+ fractional LMUL 1/8,1/4,1/2 (4 is reserved). Passing DENOMINATOR = 1
+ just applies LMUL to a plain count. */
+ static ULONGEST
+ scale_by_lmul (ULONGEST numerator, ULONGEST denominator,
+ ULONGEST vlmul) noexcept
+ {
+ if (vlmul > 4)
+ return numerator / (denominator * (1 << (8 - vlmul)));
+ return numerator * (1 << vlmul) / denominator;
+ }
+
+ ULONGEST
+ decode_imm_vector (ULONGEST ival) noexcept
+ {
+ return (ival >> OP_SH_VIMM) & OP_MASK_VIMM;
+ }
+
+ bool is_vector_unit_stride_instr (ULONGEST ival) noexcept
+ {
+ ULONGEST mop = (ival >> OP_SH_MOP) & OP_MASK_MOP;
+ bool res = (mop == 0x0);
+ if (record_debug)
+ debug_printf ("Process record: is_vector_unit_stride_instr: %d\n", res);
+ return res;
+ }
+
+ bool is_vector_unit_stride_base_instr (ULONGEST ival) noexcept
+ {
+ ULONGEST mop = (ival >> OP_SH_MOP) & OP_MASK_MOP;
+ ULONGEST umop = (ival >> OP_SH_UMOP) & OP_MASK_UMOP;
+ bool res = (mop == 0x0) && (umop == 0x0);
+ if (record_debug)
+ debug_printf ("Process record: is_vector_unit_stride_base_instr: %d\n",
+ res);
+ return res;
+ }
+
+ bool is_vector_unit_stride_whole_reg_instr (ULONGEST ival)
+ {
+ ULONGEST mop = (ival >> OP_SH_MOP) & OP_MASK_MOP;
+ ULONGEST umop = (ival >> OP_SH_UMOP) & OP_MASK_UMOP;
+ bool res = (mop == 0x0) && (umop == 0x8);
+ if (record_debug)
+ debug_printf (
+ "Process record: is_vector_unit_stride_whole_reg_instr: %d\n", res);
+ return res;
+ }
+
+ bool is_vector_strided_instr (ULONGEST ival) noexcept
+ {
+ ULONGEST mop = (ival >> OP_SH_MOP) & OP_MASK_MOP;
+ bool res = (mop == 0x2);
+ if (record_debug)
+ debug_printf ("Process record: is_vector_strided_instr: %d\n", res);
+ return res;
+ }
+
+ bool is_vector_indexed_instr (ULONGEST ival) noexcept
+ {
+ ULONGEST mop = (ival >> OP_SH_MOP) & OP_MASK_MOP;
+ bool res = (mop == 0x1) || (mop == 0x3);
+ if (record_debug)
+ debug_printf ("Process record: is_vector_indexed_instr: %d\n", res);
+ return res;
+ }
+
+ bool is_vector_load_insn (ULONGEST ival)
+ {
+ ULONGEST dummy;
+ return (((ival >> OP_SH_OP) & OP_MASK_OP) == MATCH_VECTOR_LOAD)
+ && (((ival >> OP_SH_MEW) & OP_MASK_MEW) == 0)
+ && decode_width_vector (ival, dummy);
+ }
+
+ bool is_vector_store_insn (ULONGEST ival)
+ {
+ ULONGEST dummy;
+ return (((ival >> OP_SH_OP) & OP_MASK_OP) == MATCH_VECTOR_STORE)
+ && (((ival >> OP_SH_MEW) & OP_MASK_MEW) == 0)
+ && decode_width_vector (ival, dummy);
+ }
+
+ bool is_vector_op_insn (ULONGEST ival)
+ {
+ return ((ival >> OP_SH_OP) & OP_MASK_OP) == MATCH_VECTOR_OP;
+ }
+
+ bool is_vector_vmv_nr_v_insn (ULONGEST ival)
+ {
+ return is_vmv1r_v_insn (ival) || is_vmv2r_v_insn (ival)
+ || is_vmv4r_v_insn (ival) || is_vmv8r_v_insn (ival);
+ }
+
+ bool is_vector_widening_insn (ULONGEST ival)
+ {
+ return is_vwaddu_vv_insn (ival) || is_vwaddu_vx_insn (ival)
+ || is_vwsubu_vv_insn (ival) || is_vwsubu_vx_insn (ival)
+ || is_vwadd_vv_insn (ival) || is_vwadd_vx_insn (ival)
+ || is_vwsub_vv_insn (ival) || is_vwsub_vx_insn (ival)
+ || is_vwaddu_wv_insn (ival) || is_vwaddu_wx_insn (ival)
+ || is_vwsubu_wv_insn (ival) || is_vwsubu_wx_insn (ival)
+ || is_vwadd_wv_insn (ival) || is_vwadd_wx_insn (ival)
+ || is_vwsub_wv_insn (ival) || is_vwsub_wx_insn (ival)
+ || is_vwmul_vv_insn (ival) || is_vwmul_vx_insn (ival)
+ || is_vwmulu_vv_insn (ival) || is_vwmulu_vx_insn (ival)
+ || is_vwmulsu_vv_insn (ival) || is_vwmulsu_vx_insn (ival)
+ || is_vwmaccu_vv_insn (ival) || is_vwmaccu_vx_insn (ival)
+ || is_vwmacc_vv_insn (ival) || is_vwmacc_vx_insn (ival)
+ || is_vwmaccsu_vv_insn (ival) || is_vwmaccsu_vx_insn (ival)
+ || is_vwmaccus_vx_insn (ival) || is_vwredsum_vs_insn (ival)
+ || is_vwredsumu_vs_insn (ival) || is_vfwadd_vv_insn (ival)
+ || is_vfwadd_vf_insn (ival) || is_vfwadd_wv_insn (ival)
+ || is_vfwadd_wf_insn (ival) || is_vfwsub_vv_insn (ival)
+ || is_vfwsub_vf_insn (ival) || is_vfwsub_wv_insn (ival)
+ || is_vfwsub_wf_insn (ival) || is_vfwmul_vv_insn (ival)
+ || is_vfwmul_vf_insn (ival) || is_vfwmacc_vv_insn (ival)
+ || is_vfwmacc_vf_insn (ival) || is_vfwnmacc_vv_insn (ival)
+ || is_vfwnmacc_vf_insn (ival) || is_vfwmsac_vv_insn (ival)
+ || is_vfwmsac_vf_insn (ival) || is_vfwnmsac_vv_insn (ival)
+ || is_vfwnmsac_vf_insn (ival) || is_vfwcvt_xu_f_v_insn (ival)
+ || is_vfwcvt_x_f_v_insn (ival) || is_vfwcvt_rtz_xu_f_v_insn (ival)
+ || is_vfwcvt_rtz_x_f_v_insn (ival) || is_vfwcvt_f_xu_v_insn (ival)
+ || is_vfwcvt_f_x_v_insn (ival) || is_vfwcvt_f_f_v_insn (ival)
+ || is_vfwredosum_vs_insn (ival) || is_vfwredusum_vs_insn (ival);
+ }
+
+ /* Returns true if instruction needs only saving pc and vd. */
+ bool need_save_vd (ULONGEST ival) noexcept
+ {
+ return is_vector_load_insn (ival) || is_vector_op_insn (ival);
+ }
+
+ bool try_save_n_vector_regs_from_vreg (regnum_type vreg, int n)
+ {
+ for (int i = 0; i < n; i++)
+ if (!save_reg (vreg + i))
+ return false;
+
+ if (record_debug)
+ debug_printf ("Process record: try_save_n_vector_regs_from_vreg: saving "
+ "vregs from %d to %d\n",
+ vreg, vreg + n - 1);
+
+ return true;
+ }
+
+ bool try_save_vd_helper (ULONGEST ival, ULONGEST nfields)
+ {
+ ULONGEST vtype = 0;
+ if (!read_reg (RISCV_CSR_VTYPE_REGNUM, vtype))
+ return false;
+
+ ULONGEST vlmul = vtype & 0x7;
+ ULONGEST selected_width = 0;
+ if (!decode_element_width_vector (vtype, selected_width))
+ return false;
+
+ ULONGEST encoded_width = 0;
+ if (!decode_width_vector (ival, encoded_width))
+ return false;
+
+ ULONGEST emul = scale_by_lmul (encoded_width, selected_width, vlmul);
+ emul = (emul > 0) ? emul : 1;
+
+ return try_save_n_vector_regs_from_vreg (decode_vd (ival), emul * nfields);
+ }
+
+ bool try_save_vd_vector_unit_stride (ULONGEST ival, ULONGEST nfields)
+ {
+ if (is_vector_unit_stride_whole_reg_instr (ival))
+ return try_save_n_vector_regs_from_vreg (decode_vd (ival), nfields);
+
+ return try_save_vd_helper (ival, nfields);
+ }
+
+ bool try_save_vd_vector_strided (ULONGEST ival, ULONGEST nfields)
+ {
+ return try_save_vd_helper (ival, nfields);
+ }
+
+ bool try_save_vd_vector_indexed (ULONGEST ival, ULONGEST nfields)
+ {
+ ULONGEST vtype = 0;
+ if (!read_reg (RISCV_CSR_VTYPE_REGNUM, vtype))
+ return false;
+
+ ULONGEST vlmul = vtype & 0x7;
+ ULONGEST vd_count = scale_by_lmul (1, 1, vlmul);
+ vd_count = (vd_count > 0) ? vd_count : 1;
+
+ return try_save_n_vector_regs_from_vreg (decode_vd (ival),
+ vd_count * nfields);
+ }
+
+ bool try_save_vd_vmv_nr_v (ULONGEST ival)
+ {
+ ULONGEST vd_count = (decode_imm_vector (ival) & 0x7) + 1;
+ return try_save_n_vector_regs_from_vreg (decode_vd (ival), vd_count);
+ }
+
+ bool try_save_vd_widening (ULONGEST ival)
+ {
+ ULONGEST vtype = 0;
+ if (!read_reg (RISCV_CSR_VTYPE_REGNUM, vtype))
+ return false;
+
+ ULONGEST vlmul = vtype & 0x7;
+ ULONGEST vd_count = scale_by_lmul (2, 1, vlmul);
+ vd_count = (vd_count > 0) ? vd_count : 1;
+
+ return try_save_n_vector_regs_from_vreg (decode_vd (ival), vd_count);
+ }
+
+ bool try_save_vd_vector_op (ULONGEST ival)
+ {
+ if (is_vector_vmv_nr_v_insn (ival))
+ return try_save_vd_vmv_nr_v (ival);
+
+ if (is_vector_widening_insn (ival))
+ return try_save_vd_widening (ival);
+
+ ULONGEST vtype = 0;
+ if (!read_reg (RISCV_CSR_VTYPE_REGNUM, vtype))
+ return false;
+
+ ULONGEST vlmul = vtype & 0x7;
+ ULONGEST vd_count = scale_by_lmul (1, 1, vlmul);
+ vd_count = (vd_count > 0) ? vd_count : 1;
+
+ return try_save_n_vector_regs_from_vreg (decode_vd (ival), vd_count);
+ }
+
+ /* Returns true if instruction successfully saved vd. */
+ bool try_save_vd (ULONGEST ival) noexcept
+ {
+ ULONGEST nfields = 0;
+ if (!decode_nfields_vector (ival, nfields))
+ return false;
+
+ if (is_vector_op_insn (ival))
+ return try_save_vd_vector_op (ival);
+
+ if (is_vector_unit_stride_instr (ival))
+ return try_save_vd_vector_unit_stride (ival, nfields);
+
+ if (is_vector_strided_instr (ival))
+ return try_save_vd_vector_strided (ival, nfields);
+
+ if (is_vector_indexed_instr (ival))
+ return try_save_vd_vector_indexed (ival, nfields);
+
+ warning (_ ("Unexpected vector instr: %lu"), ival);
+ return false;
+ }
+
+ bool try_save_mem_vector_unit_stride (ULONGEST ival, mem_addr addr,
+ ULONGEST nfields, ULONGEST length,
+ ULONGEST width)
+ {
+ ULONGEST vlenb_val = 0;
+ if (!read_reg (RISCV_CSR_VLENB_REGNUM, vlenb_val))
+ return false;
+
+ if (is_vector_unit_stride_whole_reg_instr (ival))
+ return save_mem (addr, nfields * vlenb_val * 8);
+
+ return save_mem (addr, nfields * length * width / 8);
+ }
+
+ bool try_save_mem_vector_strided (ULONGEST ival, mem_addr addr,
+ ULONGEST nfields, ULONGEST length,
+ ULONGEST width)
+ {
+ ULONGEST stride = 0;
+ if (!read_reg (decode_rs2 (ival), stride))
+ return false;
+
+ for (ULONGEST i = 0; i < length; ++i)
+ {
+ if (!save_mem (addr, nfields * width / 8))
+ return false;
+ addr += stride;
+ }
+
+ return true;
+ }
+
+ bool try_save_mem_vector_indexed (ULONGEST ival, mem_addr addr,
+ ULONGEST nfields, ULONGEST length,
+ ULONGEST width)
+ {
+ ULONGEST vtype_val = 0;
+ if (!read_reg (RISCV_CSR_VTYPE_REGNUM, vtype_val))
+ return false;
+
+ ULONGEST vector_elem_size = 0;
+ if (!decode_element_width_vector (vtype_val, vector_elem_size))
+ return false;
+
+ ULONGEST segment_len = nfields * vector_elem_size / 8;
+
+ regnum_type vreg = decode_vs2 (ival);
+
+ ULONGEST vtype = 0;
+ if (!read_reg (RISCV_CSR_VTYPE_REGNUM, vtype))
+ return false;
+
+ ULONGEST vlmul = vtype & 0x7;
+ ULONGEST selected_width = 0;
+ if (!decode_element_width_vector (vtype, selected_width))
+ return false;
+
+ ULONGEST encoded_width = 0;
+ if (!decode_width_vector (ival, encoded_width))
+ return false;
+
+ ULONGEST index_emul = scale_by_lmul (encoded_width, selected_width, vlmul);
+ index_emul = (index_emul > 0) ? index_emul : 1;
+
+ int vreg_size = register_size (m_regcache->arch (), RISCV_V0_REGNUM);
+ std::vector<gdb_byte> vreg_buff (vreg_size * index_emul);
+ gdb_byte *raw_p = vreg_buff.data ();
+
+ for (int i = 0; i < index_emul; ++i)
+ if (!read_vector_reg (vreg + i, raw_p + i * vreg_size))
+ return false;
+
+ gdb_byte *cur_offset_p = raw_p;
+ /* For indexed instructions, size of index depends on `width` value, so we
+ need this mask here to crop correctly here. For width == 64, byte-shift
+ approach is not working (because ULONGEST is 64-bit width). */
+ ULONGEST mask = (width == 64) ? (~ULONGEST { 0 })
+ : ((ULONGEST { 1 } << width) - 1);
+ for (ULONGEST i = 0; i < length; ++i)
+ {
+ ULONGEST cur_offset = (*reinterpret_cast<ULONGEST *> (cur_offset_p))
+ & mask;
+
+ if (!save_mem (addr + cur_offset, segment_len))
+ return false;
+
+ cur_offset_p += width / 8;
+ }
+ return true;
+ }
+
+ bool try_save_mem_vector (ULONGEST ival) noexcept
+ {
+ mem_addr addr = 0;
+ if (!read_reg (decode_rs1 (ival), addr))
+ return false;
+
+ ULONGEST nfields = 0;
+ if (!decode_nfields_vector (ival, nfields))
+ return false;
+
+ ULONGEST length = 0;
+ if (!read_reg (RISCV_CSR_VL_REGNUM, length))
+ return false;
+
+ ULONGEST width = 0;
+ if (!decode_width_vector (ival, width))
+ return false;
+
+ if (is_vector_unit_stride_instr (ival))
+ return try_save_mem_vector_unit_stride (ival, addr, nfields, length,
+ width);
+ if (is_vector_strided_instr (ival))
+ return try_save_mem_vector_strided (ival, addr, nfields, length, width);
+
+ if (is_vector_indexed_instr (ival))
+ return try_save_mem_vector_indexed (ival, addr, nfields, length, width);
+
+ warning (_ ("Unexpected vector instr: %lu"), ival);
+ return false;
+ }
+
+ bool try_save_all_vector_registers () noexcept
+ {
+ if (m_gdbarch->isa_features.vlenb)
+ {
+ return try_save_n_vector_regs_from_vreg (RISCV_V0_REGNUM, 32)
+ && save_reg (RISCV_CSR_VSTART_REGNUM)
+ && save_reg (RISCV_CSR_VCSR_REGNUM)
+ && save_reg (RISCV_CSR_VL_REGNUM)
+ && save_reg (RISCV_CSR_VTYPE_REGNUM)
+ && save_reg (RISCV_CSR_VLENB_REGNUM);
+ }
+
+ return true;
+ }
+
/* Returns true if instruction is successfully recorded. The length of
the instruction must be equal to 4 bytes. Helper function for
record_insn_len4. */
@@ -5969,6 +6443,11 @@ class riscv_recorded_insn final
return (save_reg (RISCV_CSR_MSTATUS_REGNUM)
&& save_reg (RISCV_CSR_MEPC_REGNUM));
+ if (is_vsetvli_insn (ival) || is_vsetvl_insn (ival)
+ || is_vsetivli_insn (ival))
+ return (try_save_rd (ival) && save_reg (RISCV_CSR_VTYPE_REGNUM)
+ && save_reg (RISCV_CSR_VL_REGNUM));
+
if (need_save_only_pc (ival))
return true;
@@ -5989,6 +6468,12 @@ class riscv_recorded_insn final
if (len > 0)
return try_save_rd_mem (ival, len);
+ if (need_save_vd (ival))
+ return try_save_vd (ival);
+
+ if (is_vector_store_insn (ival))
+ return try_save_mem_vector (ival);
+
warning (_("Currently this instruction with len 4(%s) is unsupported"),
hex_string (ival));
return false;
@@ -6028,6 +6513,10 @@ class riscv_recorded_insn final
mem_addr addr = 0;
ULONGEST offset = 0;
+ if (record_debug)
+ debug_printf ("Process record: record_insn_len2: record insn 0x%lx\n",
+ ival);
+
/* The order here is very important, because
opcodes of some instructions may be the same. */
diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h
index 6b5004772a1..1e53e2bf61c 100644
--- a/include/opcode/riscv-opc.h
+++ b/include/opcode/riscv-opc.h
@@ -2159,6 +2159,11 @@
#define MASK_VDOTUVV 0xfc00707f
#define MATCH_VFDOTVV 0xe4001057
#define MASK_VFDOTVV 0xfc00707f
+/* RISC-V Vector instruction formats. */
+#define MATCH_VECTOR_LOAD 0x7
+#define MATCH_VECTOR_STORE 0x27
+#define MATCH_VECTOR_OP 0x57
+#define MATCH_VECTOR_OPIVI 0x3
/* These are only used by gdb for now. */
#define MATCH_BCLRI_RV32 0x48001013
#define MASK_BCLRI_RV32 0xfe00707f
@@ -4955,6 +4960,80 @@ DECLARE_INSN(hsv_b, MATCH_HSV_B, MASK_HSV_B)
DECLARE_INSN(hsv_h, MATCH_HSV_H, MASK_HSV_H)
DECLARE_INSN(hsv_w, MATCH_HSV_W, MASK_HSV_W)
DECLARE_INSN(hsv_d, MATCH_HSV_D, MASK_HSV_D)
+/* RVV instructions. */
+DECLARE_INSN (vsetvl, MATCH_VSETVL, MASK_VSETVL)
+DECLARE_INSN (vsetvli, MATCH_VSETVLI, MASK_VSETVLI)
+DECLARE_INSN (vsetivli, MATCH_VSETIVLI, MASK_VSETIVLI)
+DECLARE_INSN (vmv1r_v, MATCH_VMV1RV, MASK_VMV1RV)
+DECLARE_INSN (vmv2r_v, MATCH_VMV2RV, MASK_VMV2RV)
+DECLARE_INSN (vmv4r_v, MATCH_VMV4RV, MASK_VMV4RV)
+DECLARE_INSN (vmv8r_v, MATCH_VMV8RV, MASK_VMV8RV)
+DECLARE_INSN (vs1r_v, MATCH_VS1RV, MASK_VS1RV)
+DECLARE_INSN (vs2r_v, MATCH_VS2RV, MASK_VS2RV)
+DECLARE_INSN (vs4r_v, MATCH_VS4RV, MASK_VS4RV)
+DECLARE_INSN (vs8r_v, MATCH_VS8RV, MASK_VS8RV)
+DECLARE_INSN (vmv_x_s, MATCH_VMVXS, MASK_VMVXS)
+DECLARE_INSN (vcpop_m, MATCH_VCPOPM, MASK_VCPOPM)
+DECLARE_INSN (vfirst_m, MATCH_VFIRSTM, MASK_VFIRSTM)
+DECLARE_INSN (vfmv_f_s, MATCH_VFMVFS, MASK_VFMVFS)
+DECLARE_INSN (vwaddu_vv, MATCH_VWADDUVV, MASK_VWADDUVV)
+DECLARE_INSN (vwaddu_vx, MATCH_VWADDUVX, MASK_VWADDUVX)
+DECLARE_INSN (vwsubu_vv, MATCH_VWSUBUVV, MASK_VWSUBUVV)
+DECLARE_INSN (vwsubu_vx, MATCH_VWSUBUVX, MASK_VWSUBUVX)
+DECLARE_INSN (vwadd_vv, MATCH_VWADDVV, MASK_VWADDVV)
+DECLARE_INSN (vwadd_vx, MATCH_VWADDVX, MASK_VWADDVX)
+DECLARE_INSN (vwsub_vv, MATCH_VWSUBVV, MASK_VWSUBVV)
+DECLARE_INSN (vwsub_vx, MATCH_VWSUBVX, MASK_VWSUBVX)
+DECLARE_INSN (vwaddu_wv, MATCH_VWADDUWV, MASK_VWADDUWV)
+DECLARE_INSN (vwaddu_wx, MATCH_VWADDUWX, MASK_VWADDUWX)
+DECLARE_INSN (vwsubu_wv, MATCH_VWSUBUWV, MASK_VWSUBUWV)
+DECLARE_INSN (vwsubu_wx, MATCH_VWSUBUWX, MASK_VWSUBUWX)
+DECLARE_INSN (vwadd_wv, MATCH_VWADDWV, MASK_VWADDWV)
+DECLARE_INSN (vwadd_wx, MATCH_VWADDWX, MASK_VWADDWX)
+DECLARE_INSN (vwsub_wv, MATCH_VWSUBWV, MASK_VWSUBWV)
+DECLARE_INSN (vwsub_wx, MATCH_VWSUBWX, MASK_VWSUBWX)
+DECLARE_INSN (vwmul_vv, MATCH_VWMULVV, MASK_VWMULVV)
+DECLARE_INSN (vwmul_vx, MATCH_VWMULVX, MASK_VWMULVX)
+DECLARE_INSN (vwmulu_vv, MATCH_VWMULUVV, MASK_VWMULUVV)
+DECLARE_INSN (vwmulu_vx, MATCH_VWMULUVX, MASK_VWMULUVX)
+DECLARE_INSN (vwmulsu_vv, MATCH_VWMULSUVV, MASK_VWMULSUVV)
+DECLARE_INSN (vwmulsu_vx, MATCH_VWMULSUVX, MASK_VWMULSUVX)
+DECLARE_INSN (vwmaccu_vv, MATCH_VWMACCUVV, MASK_VWMACCUVV)
+DECLARE_INSN (vwmaccu_vx, MATCH_VWMACCUVX, MASK_VWMACCUVX)
+DECLARE_INSN (vwmacc_vv, MATCH_VWMACCVV, MASK_VWMACCVV)
+DECLARE_INSN (vwmacc_vx, MATCH_VWMACCVX, MASK_VWMACCVX)
+DECLARE_INSN (vwmaccsu_vv, MATCH_VWMACCSUVV, MASK_VWMACCSUVV)
+DECLARE_INSN (vwmaccsu_vx, MATCH_VWMACCSUVX, MASK_VWMACCSUVX)
+DECLARE_INSN (vwmaccus_vx, MATCH_VWMACCUSVX, MASK_VWMACCUSVX)
+DECLARE_INSN (vwredsum_vs, MATCH_VWREDSUMVS, MASK_VWREDSUMVS)
+DECLARE_INSN (vwredsumu_vs, MATCH_VWREDSUMUVS, MASK_VWREDSUMUVS)
+DECLARE_INSN (vfwadd_vv, MATCH_VFWADDVV, MASK_VFWADDVV)
+DECLARE_INSN (vfwadd_vf, MATCH_VFWADDVF, MASK_VFWADDVF)
+DECLARE_INSN (vfwadd_wv, MATCH_VFWADDWV, MASK_VFWADDWV)
+DECLARE_INSN (vfwadd_wf, MATCH_VFWADDWF, MASK_VFWADDWF)
+DECLARE_INSN (vfwsub_vv, MATCH_VFWSUBVV, MASK_VFWSUBVV)
+DECLARE_INSN (vfwsub_vf, MATCH_VFWSUBVF, MASK_VFWSUBVF)
+DECLARE_INSN (vfwsub_wv, MATCH_VFWSUBWV, MASK_VFWSUBWV)
+DECLARE_INSN (vfwsub_wf, MATCH_VFWSUBWF, MASK_VFWSUBWF)
+DECLARE_INSN (vfwmul_vv, MATCH_VFWMULVV, MASK_VFWMULVV)
+DECLARE_INSN (vfwmul_vf, MATCH_VFWMULVF, MASK_VFWMULVF)
+DECLARE_INSN (vfwmacc_vv, MATCH_VFWMACCVV, MASK_VFWMACCVV)
+DECLARE_INSN (vfwmacc_vf, MATCH_VFWMACCVF, MASK_VFWMACCVF)
+DECLARE_INSN (vfwnmacc_vv, MATCH_VFWNMACCVV, MASK_VFWNMACCVV)
+DECLARE_INSN (vfwnmacc_vf, MATCH_VFWNMACCVF, MASK_VFWNMACCVF)
+DECLARE_INSN (vfwmsac_vv, MATCH_VFWMSACVV, MASK_VFWMSACVV)
+DECLARE_INSN (vfwmsac_vf, MATCH_VFWMSACVF, MASK_VFWMSACVF)
+DECLARE_INSN (vfwnmsac_vv, MATCH_VFWNMSACVV, MASK_VFWNMSACVV)
+DECLARE_INSN (vfwnmsac_vf, MATCH_VFWNMSACVF, MASK_VFWNMSACVF)
+DECLARE_INSN (vfwcvt_xu_f_v, MATCH_VFWCVTXUFV, MASK_VFWCVTXUFV)
+DECLARE_INSN (vfwcvt_x_f_v, MATCH_VFWCVTXFV, MASK_VFWCVTXFV)
+DECLARE_INSN (vfwcvt_rtz_xu_f_v, MATCH_VFWCVTRTZXUFV, MASK_VFWCVTRTZXUFV)
+DECLARE_INSN (vfwcvt_rtz_x_f_v, MATCH_VFWCVTRTZXFV, MASK_VFWCVTRTZXFV)
+DECLARE_INSN (vfwcvt_f_xu_v, MATCH_VFWCVTFXUV, MASK_VFWCVTFXUV)
+DECLARE_INSN (vfwcvt_f_x_v, MATCH_VFWCVTFXV, MASK_VFWCVTFXV)
+DECLARE_INSN (vfwcvt_f_f_v, MATCH_VFWCVTFFV, MASK_VFWCVTFFV)
+DECLARE_INSN (vfwredosum_vs, MATCH_VFWREDOSUMVS, MASK_VFWREDOSUMVS)
+DECLARE_INSN (vfwredusum_vs, MATCH_VFWREDUSUMVS, MASK_VFWREDUSUMVS)
/* Zicbop instructions. */
DECLARE_INSN(prefetch_r, MATCH_PREFETCH_R, MASK_PREFETCH_R)
DECLARE_INSN(prefetch_w, MATCH_PREFETCH_W, MASK_PREFETCH_W)
diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
index 95b1f44567a..881597d342a 100644
--- a/include/opcode/riscv.h
+++ b/include/opcode/riscv.h
@@ -368,6 +368,16 @@ static inline unsigned int riscv_insn_length (insn_t insn)
#define OP_MASK_VMASK 0x1
#define OP_SH_VMASK 25
#define OP_MASK_VFUNCT6 0x3f
+#define OP_SH_MOP 26
+#define OP_MASK_MOP 0x3
+#define OP_SH_WIDTH 12
+#define OP_MASK_WIDTH 0x7
+#define OP_SH_MEW 28
+#define OP_MASK_MEW 0x1
+#define OP_SH_NF 29
+#define OP_MASK_NF 0x7
+#define OP_SH_UMOP 20
+#define OP_MASK_UMOP 0x1f
#define OP_SH_VFUNCT6 26
#define OP_MASK_VLMUL 0x7
#define OP_SH_VLMUL 0
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 3/3] RISC-V Vector Extension Support Testing
2026-09-25 17:29 [PATCH v2 0/3] RISC-V Vector Extension support Kirill Radkin
2026-09-25 17:29 ` [PATCH v2 1/3] RISC-V Vector Extension Support Kirill Radkin
2026-09-25 17:29 ` [PATCH v2 2/3] Reverse execution support for RISC-V Vector Extension Kirill Radkin
@ 2026-09-25 17:29 ` Kirill Radkin
2 siblings, 0 replies; 4+ messages in thread
From: Kirill Radkin @ 2026-09-25 17:29 UTC (permalink / raw)
To: gdb-patches
Cc: Peter Bergner, Sergey Matyukevich, Jerry Zhang Jian,
Heinrich Schuchardt, Andrew Burgess, Palmer Dabbelt
This patch add extensive testing for RISC-V Vector Extension Support.
---
...iscv-vector-abi-full-generate-template.txt | 176 ++++++++
.../riscv-vector-abi-full-generate.py | 384 ++++++++++++++++++
.../gdb.arch/riscv-vector-abi-full.c | 23 ++
.../gdb.arch/riscv-vector-abi-full.exp | 72 ++++
gdb/testsuite/gdb.arch/riscv-vector-abi.c | 157 +++++++
gdb/testsuite/gdb.arch/riscv-vector-abi.exp | 247 +++++++++++
.../gdb.arch/riscv-vu-availability.c | 67 +++
.../gdb.arch/riscv-vu-availability.exp | 72 ++++
.../gdb.arch/riscv-vu-consitency-checks.c | 79 ++++
.../gdb.arch/riscv-vu-consitency-checks.exp | 156 +++++++
gdb/testsuite/gdb.arch/riscv-vu-ctx-print.c | 106 +++++
gdb/testsuite/gdb.arch/riscv-vu-ctx-print.exp | 107 +++++
gdb/testsuite/gdb.arch/riscv-vu-printout.c | 69 ++++
gdb/testsuite/gdb.arch/riscv-vu-printout.exp | 92 +++++
.../gdb.arch/riscv-vu-rvv-unsupported.c | 23 ++
.../gdb.arch/riscv-vu-rvv-unsupported.exp | 46 +++
gdb/testsuite/gdb.arch/riscv-vu-rwr.c | 62 +++
gdb/testsuite/gdb.arch/riscv-vu-rwr.exp | 173 ++++++++
.../gdb.arch/riscv-vu-side-effects.c | 86 ++++
.../gdb.arch/riscv-vu-side-effects.exp | 162 ++++++++
gdb/testsuite/lib/gdb.exp | 124 ++++++
gdb/testsuite/lib/riscv64-rvv-lib.exp | 347 ++++++++++++++++
22 files changed, 2830 insertions(+)
create mode 100644 gdb/testsuite/gdb.arch/riscv-vector-abi-full-generate-template.txt
create mode 100644 gdb/testsuite/gdb.arch/riscv-vector-abi-full-generate.py
create mode 100644 gdb/testsuite/gdb.arch/riscv-vector-abi-full.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vector-abi-full.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vector-abi.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vector-abi.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-availability.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-availability.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-consitency-checks.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-consitency-checks.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-ctx-print.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-ctx-print.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-printout.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-printout.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-rvv-unsupported.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-rvv-unsupported.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-rwr.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-rwr.exp
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-side-effects.c
create mode 100644 gdb/testsuite/gdb.arch/riscv-vu-side-effects.exp
create mode 100644 gdb/testsuite/lib/riscv64-rvv-lib.exp
diff --git a/gdb/testsuite/gdb.arch/riscv-vector-abi-full-generate-template.txt b/gdb/testsuite/gdb.arch/riscv-vector-abi-full-generate-template.txt
new file mode 100644
index 00000000000..0e364cd9611
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vector-abi-full-generate-template.txt
@@ -0,0 +1,176 @@
+{#
+Copyright 2026 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+#}
+
+{% macro main_header(file) -%}
+/* DO NOT EDIT: Autogenerated by {{ file }}
+ Copyright 2026 Free Software Foundation, Inc.
+ This file is part of GDB, the GNU debugger. */
+
+#include <riscv_vector.h>
+{% endmacro %}
+
+{% macro main_tail_start() %}
+void
+test ()
+{
+ size_t vl = 0;
+{% endmacro %}
+
+{% macro expect_header(file) -%}
+# DO NOT EDIT: Autogenerated by {{ file }}
+# Copyright 2026 Free Software Foundation, Inc.
+# This file is part of GDB, the GNU debugger.
+
+proc generate_response { start step count } {
+ if {$step == 0 && $count > 8} {
+ return "\\{${start} <repeats ${count} times>\\}"
+ }
+
+ set res "\\{$start"
+ set count [expr {$count - 1}]
+
+ for {set i 0} {$i < $count} {incr i} {
+ set start [expr {$start + $step}]
+ set res "${res}, $start"
+ }
+ set res "${res}\\}"
+ return $res
+}
+
+proc generate_tuple_response { nfields starts step count } {
+ set fields {}
+ for {set i 0} {$i < $nfields} {incr i} {
+ set start [lindex $starts $i]
+ lappend fields [generate_response $start $step $count]
+ }
+ return [riscvlib_rvv_tuple_pattern $fields]
+}
+
+proc test_print_with_rvv_state_check { command regexp } {
+ set vector_state_before_call [capture_command_output "info vector" ""]
+
+ gdb_test $command $regexp
+
+ set vector_state_after_call [capture_command_output "info vector" ""]
+ if ![string compare $vector_state_before_call $vector_state_after_call] {
+ pass "vector state was saved/restored correctly during $command"
+ } else {
+ fail "vector state wasn't saved/restored correctly durring $command"
+ }
+}
+
+standard_testfile [standard_output_file riscv-vector-abi-full-generated.c]
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile $compile_flags]} {
+ return -1
+}
+
+if {![runto_main]} {
+ return -1
+}
+{% endmacro %}
+
+{% macro func_name_template(type_name) -%}
+add_{{ type_name }}
+{%- endmacro %}
+
+{% macro func_template(type_name, vadd_name, func_name, vsetvlmax) -%}
+{{ type_name }}
+{{ func_name }} ({{ type_name }} a, {{ type_name }} b)
+{
+ size_t vl = {{ vsetvlmax }} ();
+ return {{ vadd_name }} (a, b, vl);
+}
+
+{% endmacro %}
+
+{% macro main_entry_template(type_name, var_idx, vmv_name, var_val, func_name, vsetvlmax) %}
+ // {{ type_name }}
+ vl = {{ vsetvlmax }} ();
+ {{ type_name }} var{{ var_idx }} = {{ vmv_name }} ({{ var_val }}, vl);
+ {{ type_name }} res{{ var_idx }} = {{ func_name }} (var{{ var_idx }}, var{{ var_idx }});
+ // {{ type_name }}_break
+{% endmacro %}
+
+{% macro test_entry_template(main_file, type_name, break_idx, var_idx, var_val, res_val, func_name) %}
+gdb_breakpoint "[host_standard_output_file {{ main_file }}]:[gdb_get_line_number "{{ type_name }}_break"]"
+gdb_continue_to_breakpoint "break {{ break_idx }}"
+set vl [get_valueof "/d" "vl" -1 "get_vl_{{ break_idx }}"]
+gdb_test "print var{{ var_idx }}" "[generate_response {{ var_val }} 0 $vl]"
+gdb_test "print res{{ var_idx }}" "[generate_response {{ res_val }} 0 $vl]"
+test_print_with_rvv_state_check "print {{ func_name }} (var{{ var_idx }}, var{{ var_idx }})" "[generate_response {{ res_val }} 0 $vl]"
+{% endmacro %}
+
+{% macro tuple_func_template_start() %}
+{type_name}
+{func_name} ({type_name} a, {type_name} b)
+{{ '{{' }}
+ {type_name} result;
+ size_t vl = {vsetvlmax} ();
+{% endmacro %}
+
+{% macro tuple_func_template_entry(index) %}
+ {short_type_name} a{{ index }} = {vget_name} (a, {{ index }});
+ {short_type_name} b{{ index }} = {vget_name} (b, {{ index }});
+ {short_type_name} r{{ index }} = {vadd_name} (a{{ index }}, b{{ index }}, vl);
+ result = {vset_name} (result, {{ index }}, r{{ index }});
+{% endmacro %}
+
+{% macro tuple_func_template_end() %}
+ return result;
+{{ '}}' }}
+{% endmacro %}
+
+{% macro tuple_main_entry_template_start() %}
+ // {type_name}
+ vl = {vsetvlmax} ();
+ {type_name} var{var_idx};
+{% endmacro %}
+
+{% macro tuple_main_entry_template_entry(index) %}
+ {short_type_name} var{var_idx}_{{ index }} = {vmv_name} ({var_values[{{ index }}]}, vl);
+ var{var_idx} = {vset_name} (var{var_idx}, {{ index }}, var{var_idx}_{{ index }});
+{% endmacro %}
+
+{% macro tuple_main_entry_template_end() %}
+ {type_name} res{var_idx} = {func_name} (var{var_idx}, var{var_idx});
+ // {type_name}_break
+{% endmacro %}
+
+{% macro tuple_test_template_start(main_file) %}
+gdb_breakpoint "[host_standard_output_file {{ main_file }}]:[gdb_get_line_number "{type_name}_break"]"
+gdb_continue_to_breakpoint "break {break_idx}"
+set vl [get_valueof "/d" "vl" -1 "get_vl_{break_idx}"]
+{% endmacro %}
+
+{% macro tuple_test_template_entry_first(index) -%}
+gdb_test "print var{var_idx}_{{ index }}" "[generate_response {var_values[{{ index }}]} 0 $vl]"
+{% endmacro %}
+
+{% macro tuple_test_template_entry_middle() -%}
+set res_values {{ '{{' }}
+{%- endmacro %}
+
+{% macro tuple_test_template_entry_second(index) -%}
+{{ ' ' }}{{ '{{' }}{res_values[{{ index }}]}{{ '}}' }}
+{%- endmacro %}
+
+{% macro tuple_test_template_end(nfields) -%}
+{{ ' }}' }}
+gdb_test "print res{var_idx}" "[generate_tuple_response {{ nfields }} $res_values 0 $vl]"
+test_print_with_rvv_state_check "print {func_name} (var{var_idx}, var{var_idx})" "[generate_tuple_response {{ nfields }} $res_values 0 $vl]"
+{% endmacro %}
diff --git a/gdb/testsuite/gdb.arch/riscv-vector-abi-full-generate.py b/gdb/testsuite/gdb.arch/riscv-vector-abi-full-generate.py
new file mode 100644
index 00000000000..36de27fe64c
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vector-abi-full-generate.py
@@ -0,0 +1,384 @@
+# Copyright 2026 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import itertools
+import re
+from pathlib import Path
+from enum import Enum
+from jinja2 import Environment, FileSystemLoader
+
+FILE = Path(__file__).name
+TEST_DIR = Path(__file__).resolve().parent
+JINJA_TEMPLATE_FILE = "riscv-vector-abi-full-generate-template.txt"
+
+WORK_DIR = os.getenv("WORK_DIR")
+TEST_NAME = os.getenv("TEST_NAME")
+HAS_ZVFH = os.getenv("HAS_ZVFH") == "1"
+
+
+class ElemType(str, Enum):
+ INT = "int"
+ UINT = "uint"
+ FLOAT = "float"
+
+
+class InstrType(str, Enum):
+ VADD = "vadd"
+ VMV = "vmv"
+ VGET = "vget"
+ VSET = "vset"
+ VSETVLMAX = "vlmax"
+
+
+class InstructionTemplate:
+ vadd_instr_templates = {
+ ElemType.INT: "__riscv_vadd_vv_i{suffix1}",
+ ElemType.UINT: "__riscv_vadd_vv_u{suffix1}",
+ ElemType.FLOAT: "__riscv_vfadd_vv_f{suffix1}",
+ }
+
+ vmv_instr_templates = {
+ ElemType.INT: "__riscv_vmv_v_x_i{suffix1}",
+ ElemType.UINT: "__riscv_vmv_v_x_u{suffix1}",
+ ElemType.FLOAT: "__riscv_vfmv_v_f_f{suffix1}",
+ }
+
+ vget_instr_templates = {
+ ElemType.INT: "__riscv_vget_v_i{suffix1}_i{suffix2}",
+ ElemType.UINT: "__riscv_vget_v_u{suffix1}_u{suffix2}",
+ ElemType.FLOAT: "__riscv_vget_v_f{suffix1}_f{suffix2}",
+ }
+
+ vset_instr_templates = {
+ ElemType.INT: "__riscv_vset_v_i{suffix1}_i{suffix2}",
+ ElemType.UINT: "__riscv_vset_v_u{suffix1}_u{suffix2}",
+ ElemType.FLOAT: "__riscv_vset_v_f{suffix1}_f{suffix2}",
+ }
+
+ vsetvlmax_template = {k: "__riscv_vsetvlmax_e{suffix1}" for k in ElemType}
+
+ templates = {
+ InstrType.VADD: vadd_instr_templates,
+ InstrType.VMV: vmv_instr_templates,
+ InstrType.VGET: vget_instr_templates,
+ InstrType.VSET: vset_instr_templates,
+ InstrType.VSETVLMAX: vsetvlmax_template,
+ }
+
+ def get(self, elem_type: ElemType, instr_type: InstrType):
+ return self.templates[instr_type][elem_type]
+
+
+def generate(directory: Path, test_name: Path):
+ instr_templates = InstructionTemplate()
+
+ env = Environment(loader=FileSystemLoader(str(TEST_DIR)))
+ tpl = env.get_template(str(JINJA_TEMPLATE_FILE))
+
+ counter_vars = itertools.count(0)
+ counter_values = itertools.cycle(range(0, 64, 1))
+ counter_break_idx = itertools.count(2)
+
+ main_file = Path(f"{test_name}.c")
+ main_file_path = directory / main_file
+
+ test_script = Path(f"{test_name}.exp")
+ test_script_path = directory / test_script
+
+ if not os.path.exists(main_file_path):
+ os.mknod(main_file_path)
+
+ if not os.path.exists(test_script_path):
+ os.mknod(test_script_path)
+
+ main_header = tpl.module.main_header(FILE)
+
+ with open(main_file_path, "w") as f:
+ f.write(main_header)
+
+ main_tail = tpl.module.main_tail_start()
+
+ expect_header = tpl.module.expect_header(FILE)
+
+ with open(test_script_path, "w") as f:
+ f.write(expect_header)
+
+ # int, uint, float
+
+ # fmt: off
+ vint_types = [
+ # 8-bit
+ "vint8mf8_t", "vint8mf4_t", "vint8mf2_t", "vint8m1_t", "vint8m2_t", "vint8m4_t", "vint8m8_t",
+
+ # 16-bit
+ "vint16mf4_t", "vint16mf2_t", "vint16m1_t", "vint16m2_t", "vint16m4_t", "vint16m8_t",
+
+ # 32-bit
+ "vint32mf2_t", "vint32m1_t", "vint32m2_t", "vint32m4_t", "vint32m8_t",
+
+ # 64-bit
+ "vint64m1_t", "vint64m2_t", "vint64m4_t", "vint64m8_t",
+ ]
+
+ vuint_types = [_.replace("int", "uint") for _ in vint_types]
+
+ vfloat_types = []
+ if HAS_ZVFH:
+ vfloat_types += [
+ # SEW = 16 (half-precision)
+ "vfloat16mf4_t", "vfloat16mf2_t", "vfloat16m1_t", "vfloat16m2_t", "vfloat16m4_t", "vfloat16m8_t",
+ ]
+
+ vfloat_types += [
+ # SEW = 32 (single-precision)
+ "vfloat32mf2_t", "vfloat32m1_t", "vfloat32m2_t", "vfloat32m4_t", "vfloat32m8_t",
+
+ # SEW = 64 (double-precision)
+ "vfloat64m1_t", "vfloat64m2_t", "vfloat64m4_t", "vfloat64m8_t",
+ ]
+ # fmt: on
+
+ for type_name in vint_types + vuint_types + vfloat_types:
+ m = re.match(r"v(int|uint|float)(8|16|32|64)(m|mf)(1|2|4|8)_t", type_name)
+ if not m:
+ raise RuntimeError("wrong type")
+
+ elem_type = ElemType(m.group(1))
+ small_suffix = "".join(m.group(2, 3, 4)) # 16m2
+
+ func_name = tpl.module.func_name_template(type_name)
+ vsetvlmax = instr_templates.get(elem_type, InstrType.VSETVLMAX).format(
+ suffix1=small_suffix
+ )
+ vadd_name = instr_templates.get(elem_type, InstrType.VADD).format(
+ suffix1=small_suffix
+ )
+ vmv_name = instr_templates.get(elem_type, InstrType.VMV).format(
+ suffix1=small_suffix
+ )
+
+ var_idx = next(counter_vars)
+ var_val = next(counter_values)
+ res_val = 2 * var_val
+
+ new_line = tpl.module.func_template(
+ type_name,
+ vadd_name,
+ func_name,
+ vsetvlmax,
+ )
+
+ with open(main_file_path, "a") as f:
+ f.write(new_line)
+
+ main_tail += tpl.module.main_entry_template(
+ type_name,
+ var_idx,
+ vmv_name,
+ var_val,
+ func_name,
+ vsetvlmax,
+ )
+
+ break_idx = next(counter_break_idx)
+ test_command = tpl.module.test_entry_template(
+ main_file,
+ type_name,
+ break_idx,
+ var_idx,
+ var_val,
+ res_val,
+ func_name,
+ )
+ with open(test_script_path, "a") as f:
+ f.write(test_command)
+
+ # tuple int
+
+ # fmt: off
+ vint_tuple_types = [
+ # LMUL = mf8
+ "vint8mf8x2_t", "vint8mf8x3_t", "vint8mf8x4_t", "vint8mf8x5_t", "vint8mf8x6_t", "vint8mf8x7_t", "vint8mf8x8_t",
+
+ # LMUL = mf4
+ "vint8mf4x2_t", "vint8mf4x3_t", "vint8mf4x4_t", "vint8mf4x5_t", "vint8mf4x6_t", "vint8mf4x7_t", "vint8mf4x8_t",
+ "vint16mf4x2_t", "vint16mf4x3_t", "vint16mf4x4_t", "vint16mf4x5_t", "vint16mf4x6_t", "vint16mf4x7_t", "vint16mf4x8_t",
+
+ # LMUL = mf2
+ "vint8mf2x2_t", "vint8mf2x3_t", "vint8mf2x4_t", "vint8mf2x5_t", "vint8mf2x6_t", "vint8mf2x7_t", "vint8mf2x8_t",
+ "vint16mf2x2_t", "vint16mf2x3_t", "vint16mf2x4_t", "vint16mf2x5_t", "vint16mf2x6_t", "vint16mf2x7_t", "vint16mf2x8_t",
+ "vint32mf2x2_t", "vint32mf2x3_t", "vint32mf2x4_t", "vint32mf2x5_t", "vint32mf2x6_t", "vint32mf2x7_t", "vint32mf2x8_t",
+
+ # LMUL = m1
+ "vint8m1x2_t", "vint8m1x3_t", "vint8m1x4_t", "vint8m1x5_t", "vint8m1x6_t", "vint8m1x7_t", "vint8m1x8_t",
+ "vint16m1x2_t", "vint16m1x3_t", "vint16m1x4_t", "vint16m1x5_t", "vint16m1x6_t", "vint16m1x7_t", "vint16m1x8_t",
+ "vint32m1x2_t", "vint32m1x3_t", "vint32m1x4_t", "vint32m1x5_t", "vint32m1x6_t", "vint32m1x7_t", "vint32m1x8_t",
+ "vint64m1x2_t", "vint64m1x3_t", "vint64m1x4_t", "vint64m1x5_t", "vint64m1x6_t", "vint64m1x7_t", "vint64m1x8_t",
+
+ # LMUL = m2
+ "vint8m2x2_t", "vint8m2x3_t", "vint8m2x4_t",
+ "vint16m2x2_t", "vint16m2x3_t", "vint16m2x4_t",
+ "vint32m2x2_t", "vint32m2x3_t", "vint32m2x4_t",
+ "vint64m2x2_t", "vint64m2x3_t", "vint64m2x4_t",
+
+ # LMUL = m4
+ "vint8m4x2_t",
+ "vint16m4x2_t",
+ "vint32m4x2_t",
+ "vint64m4x2_t",
+ ]
+
+ vuint_tuple_types = [_.replace("int", "uint") for _ in vint_tuple_types]
+
+ vfloat_tuple_types = []
+ if HAS_ZVFH:
+ vfloat_tuple_types += [
+ # vfloat16
+ "vfloat16mf4x2_t", "vfloat16mf4x3_t", "vfloat16mf4x4_t", "vfloat16mf4x5_t",
+ "vfloat16mf4x6_t", "vfloat16mf4x7_t", "vfloat16mf4x8_t",
+ "vfloat16mf2x2_t", "vfloat16mf2x3_t", "vfloat16mf2x4_t", "vfloat16mf2x5_t",
+ "vfloat16mf2x6_t", "vfloat16mf2x7_t", "vfloat16mf2x8_t",
+ "vfloat16m1x2_t", "vfloat16m1x3_t", "vfloat16m1x4_t", "vfloat16m1x5_t",
+ "vfloat16m1x6_t", "vfloat16m1x7_t", "vfloat16m1x8_t",
+ "vfloat16m2x2_t", "vfloat16m2x3_t", "vfloat16m2x4_t",
+ "vfloat16m4x2_t",
+ ]
+
+ vfloat_tuple_types += [
+ # LMUL = mf2 (1/2)
+ "vfloat32mf2x2_t", "vfloat32mf2x3_t", "vfloat32mf2x4_t", "vfloat32mf2x5_t",
+ "vfloat32mf2x6_t", "vfloat32mf2x7_t", "vfloat32mf2x8_t",
+
+ # LMUL = m1 (1)
+ "vfloat32m1x2_t", "vfloat32m1x3_t", "vfloat32m1x4_t", "vfloat32m1x5_t",
+ "vfloat32m1x6_t", "vfloat32m1x7_t", "vfloat32m1x8_t",
+ "vfloat64m1x2_t", "vfloat64m1x3_t", "vfloat64m1x4_t", "vfloat64m1x5_t",
+ "vfloat64m1x6_t", "vfloat64m1x7_t", "vfloat64m1x8_t",
+
+ # LMUL = m2 (2)
+ "vfloat32m2x2_t", "vfloat32m2x3_t", "vfloat32m2x4_t",
+ "vfloat64m2x2_t", "vfloat64m2x3_t", "vfloat64m2x4_t",
+
+ # LMUL = m4 (4)
+ "vfloat32m4x2_t",
+ "vfloat64m4x2_t",
+ ]
+ # fmt: on
+
+ def get_tuple_template(nfields: int) -> str:
+ tuple_template = tpl.module.tuple_func_template_start()
+ for i in range(nfields):
+ tuple_template += tpl.module.tuple_func_template_entry(i)
+ tuple_template += tpl.module.tuple_func_template_end()
+ return tuple_template
+
+ def get_main_tuple_template(nfields: int) -> str:
+ main_tuple_template = tpl.module.tuple_main_entry_template_start()
+ for i in range(nfields):
+ main_tuple_template += tpl.module.tuple_main_entry_template_entry(i)
+ main_tuple_template += tpl.module.tuple_main_entry_template_end()
+ return main_tuple_template
+
+ def get_test_tuple_template(nfields: int) -> str:
+ test_tuple_template = tpl.module.tuple_test_template_start(main_file)
+ for i in range(nfields):
+ test_tuple_template += tpl.module.tuple_test_template_entry_first(i)
+ test_tuple_template += tpl.module.tuple_test_template_entry_middle()
+ for i in range(nfields):
+ test_tuple_template += tpl.module.tuple_test_template_entry_second(i)
+ test_tuple_template += tpl.module.tuple_test_template_end(nfields)
+ return test_tuple_template
+
+ for type_name in vint_tuple_types + vuint_tuple_types + vfloat_tuple_types:
+ m = re.match(
+ r"v(int|uint|float)(8|16|32|64)(m|mf)(1|2|4|8)(x)([2-8])_t",
+ type_name,
+ )
+ if not m:
+ raise RuntimeError("wrong type")
+
+ elem_type = ElemType(m.group(1))
+ nfields = int(m.group(6))
+ short = type_name[:-4] + "_t"
+ big_suffix = "".join(m.group(2, 3, 4, 5, 6)) # 16m2x3
+ small_suffix = "".join(m.group(2, 3, 4)) # 16m2
+
+ func_name = tpl.module.func_name_template(type_name)
+ vsetvlmax = instr_templates.get(elem_type, InstrType.VSETVLMAX).format(
+ suffix1=small_suffix
+ )
+ vget_name = instr_templates.get(elem_type, InstrType.VGET).format(
+ suffix1=big_suffix, suffix2=small_suffix
+ )
+ vadd_name = instr_templates.get(elem_type, InstrType.VADD).format(
+ suffix1=small_suffix
+ )
+ vset_name = instr_templates.get(elem_type, InstrType.VSET).format(
+ suffix1=small_suffix, suffix2=big_suffix
+ )
+ vmv_name = instr_templates.get(elem_type, InstrType.VMV).format(
+ suffix1=small_suffix
+ )
+
+ var_idx = next(counter_vars)
+ var_values = [val for _, val in zip(range(nfields), counter_values)]
+ res_values = [2 * val for val in var_values]
+
+ string = get_tuple_template(nfields).format(
+ type_name=type_name,
+ short_type_name=short,
+ vget_name=vget_name,
+ vadd_name=vadd_name,
+ vset_name=vset_name,
+ func_name=func_name,
+ vsetvlmax=vsetvlmax,
+ )
+
+ with open(main_file_path, "a") as f:
+ f.write(string)
+
+ main_tail += get_main_tuple_template(nfields).format(
+ vsetvlmax=vsetvlmax,
+ short_type_name=short,
+ var_idx=var_idx,
+ small_suffix=small_suffix,
+ type_name=type_name,
+ vset_name=vset_name,
+ func_name=func_name,
+ vmv_name=vmv_name,
+ var_values=var_values,
+ )
+
+ break_idx = next(counter_break_idx)
+ test_command = get_test_tuple_template(nfields).format(
+ type_name=type_name,
+ break_idx=break_idx,
+ var_idx=var_idx,
+ var_values=var_values,
+ res_values=res_values,
+ func_name=func_name,
+ )
+
+ with open(test_script_path, "a") as f:
+ f.write(test_command)
+
+ with open(main_file_path, "a") as f:
+ f.write(main_tail)
+ f.write("\n return;\n}\n")
+ f.write("\nint main () {test();}\n")
+
+
+generate(WORK_DIR, TEST_NAME)
diff --git a/gdb/testsuite/gdb.arch/riscv-vector-abi-full.c b/gdb/testsuite/gdb.arch/riscv-vector-abi-full.c
new file mode 100644
index 00000000000..bab7bd129fe
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vector-abi-full.c
@@ -0,0 +1,23 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2026 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+int
+main ()
+{
+ __asm__ __volatile__ ("vsetvli t0, x0, e8, m1, ta, ma" : : : "t0");
+ return 0; /* break 2 */
+}
diff --git a/gdb/testsuite/gdb.arch/riscv-vector-abi-full.exp b/gdb/testsuite/gdb.arch/riscv-vector-abi-full.exp
new file mode 100644
index 00000000000..9a24080b429
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vector-abi-full.exp
@@ -0,0 +1,72 @@
+# Copyright 2026 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+load_lib riscv64-rvv-lib.exp
+
+if {[catch {exec python3 -c "import jinja2"} result]} {
+ unsupported "python3 with jinja2 is required"
+ return
+}
+
+if {![riscv_support_rvv]} {
+ unsupported "RVV unsupported"
+ return
+}
+
+if {![riscv_support_rvv_intrinsic]} {
+ unsupported "RVV intrinsic unsupported"
+ return
+}
+
+standard_testfile
+
+set compile_flags {"debug"}
+lappend compile_flags "additional_flags=-march=rv64gcv"
+
+# First, we figure out VLENB value to set correct vector extension to march
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile $compile_flags]} {
+ return -1
+}
+
+if {![runto_main]} {
+ return -1
+}
+
+gdb_breakpoint "$srcfile:[gdb_get_line_number "break 2"]"
+gdb_continue_to_breakpoint "preparing stage"
+set vlenb [riscvlib_rvv_get_csr vlenb "$testfile"]
+
+set compile_flags {"debug"}
+if {$vlenb >= 16} {
+ set march rv64gcv
+} elseif {$vlenb >= 8} {
+ set march rv64gc_zve64d
+} else {
+ unsupported "Unsupported VLENB value: $vlenb"
+ return
+}
+
+set has_zvfh [riscv_support_zvfh]
+if {$has_zvfh} {
+ append march _zvfh
+}
+lappend compile_flags "additional_flags=-march=$march"
+
+set env(WORK_DIR) [standard_output_file ""]
+set env(TEST_NAME) riscv-vector-abi-full-generated
+set env(HAS_ZVFH) $has_zvfh
+exec python3 $srcdir/$subdir/riscv-vector-abi-full-generate.py
+
+source [standard_output_file riscv-vector-abi-full-generated.exp]
diff --git a/gdb/testsuite/gdb.arch/riscv-vector-abi.c b/gdb/testsuite/gdb.arch/riscv-vector-abi.c
new file mode 100644
index 00000000000..71546baa114
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vector-abi.c
@@ -0,0 +1,157 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2026 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <riscv_vector.h>
+#include <malloc.h>
+
+unsigned
+do_vlen_read ()
+{
+ unsigned vlenb;
+ asm volatile ("csrr %[vlenb], vlenb" : [vlenb] "=r"(vlenb) : :);
+ /* According to vector spec: "vlenb holds the value VLEN/8". */
+ return vlenb * 8;
+}
+
+vint64m1_t
+foo (vint64m1_t a, vint32mf2_t b, vint64m1_t c, size_t n)
+{
+ vint64m1_t tmp = __riscv_vwadd_wv_i64m1 (a, b, n);
+ return __riscv_vadd_vv_i64m1 (c, tmp, n);
+}
+
+vint32m4_t
+foo1 (vint32m4_t a, vint16m2_t b, size_t n)
+{
+ return __riscv_vwadd_wv_i32m4 (a, b, n);
+}
+
+vint32m4_t
+foo2 (vint16m2_t a, vint32m4_t b, size_t n)
+{
+ return __riscv_vwadd_wv_i32m4 (b, a, n);
+}
+
+vint64m8_t
+foo3 (vint64m8_t a, vint64m8_t b, vint64m8_t c, size_t n)
+{
+ vint64m8_t tmp = __riscv_vadd_vv_i64m8 (a, b, n);
+ return __riscv_vadd_vv_i64m8 (tmp, c, n);
+}
+
+vint64m8_t
+foo4 (vint64m8_t a, vint64m8_t b, vbool8_t mask, vbool8_t mask2, size_t n)
+{
+ return __riscv_vadd_vv_i64m8_m (mask2, a, b, n);
+}
+
+vint32m4_t
+foo5_get0 (vint16m2_t tmp_a, vint32m4x2_t a)
+{
+ return __riscv_vget_v_i32m4x2_i32m4 (a, 0);
+}
+
+vint32m4_t
+foo5_get1 (vint16m2_t tmp_a, vint32m4x2_t a)
+{
+ return __riscv_vget_v_i32m4x2_i32m4 (a, 1);
+}
+
+vint32mf2_t
+foo6_get0 (vint16m2_t tmp_a, vint32mf2x2_t a)
+{
+ return __riscv_vget_v_i32mf2x2_i32mf2 (a, 0);
+}
+
+vint32mf2_t
+foo6_get1 (vint16m2_t tmp_a, vint32mf2x2_t a)
+{
+ return __riscv_vget_v_i32mf2x2_i32mf2 (a, 1);
+}
+
+int
+main ()
+{
+ unsigned n = do_vlen_read () / 64;
+ vint64m1_t a = __riscv_vmv_v_x_i64m1 (42, n);
+ vint32mf2_t b = __riscv_vmv_v_x_i32mf2 (43, n);
+ vint64m1_t c = __riscv_vmv_v_x_i64m1 (44, n);
+
+ vint64m1_t res = foo (a, b, c, n);
+ /* break 2 */
+
+ n = do_vlen_read () * 4 / 32;
+ vint32m4_t g = __riscv_vmv_v_x_i32m4 (48, n);
+ vint16m2_t h = __riscv_vmv_v_x_i16m2 (49, n);
+
+ vint32m4_t res_1 = foo1 (g, h, n); // g is on v8-v11, h is on v12-v13
+ vint32m4_t res_2 = foo2 (h, g, n); // h is on v8-v9, g is on v12-v15
+ /* break 3 */
+
+ n = do_vlen_read () * 8 / 64;
+ vint64m8_t big1 = __riscv_vmv_v_x_i64m8 (50, n);
+ vint64m8_t big2 = __riscv_vmv_v_x_i64m8 (51, n);
+ vint64m8_t big3 = __riscv_vmv_v_x_i64m8 (52, n);
+ vint64m8_t big_res = foo3 (big1, big2, big3, n);
+ /* break 4 */
+
+ unsigned mask_size = n / 8;
+ uint8_t *rs1_mask = malloc (mask_size * sizeof (uint8_t));
+ for (int i = 0; i < mask_size; i++)
+ rs1_mask[i] = 0xa5;
+
+ vbool8_t mask = __riscv_vlm_v_b8 (rs1_mask, n);
+ vint64m8_t masked_sum = foo4 (big1, big2, mask, mask, n);
+ /* break 5 */
+
+ n = do_vlen_read () * 4 * 2 / 32;
+ unsigned addr_size = n / 2;
+ uint32_t *addr = malloc (addr_size * sizeof (uint32_t));
+ for (unsigned i = 0; i < addr_size; i++)
+ addr[i] = 8 * (uint32_t) i;
+
+ vuint32m4_t rs2 = __riscv_vle32_v_u32m4 (addr, addr_size);
+ /* break 6 */
+
+ int32_t *rs1 = malloc (n * sizeof (*rs1));
+ for (int i = 0; i < n; i++)
+ rs1[i] = (int32_t) i;
+
+ vint32m4x2_t a_seg = __riscv_vluxseg2ei32_v_i32m4x2 (rs1, rs2, n);
+ /* break 7 */
+ vint32m4_t res_a_seg0 = foo5_get0 (h, a_seg);
+ /* break 8 */
+ vint32m4_t res_a_seg1 = foo5_get1 (h, a_seg);
+ /* break 9 */
+
+ vuint32mf2_t rs2_2 = __riscv_vle32_v_u32mf2 (addr, addr_size);
+ /* break 10 */
+
+ n = do_vlen_read () / 32;
+ vint32mf2x2_t b_seg = __riscv_vluxseg2ei32_v_i32mf2x2 (rs1, rs2_2, n);
+ /* break 11 */
+ vint32mf2_t res_b_seg0 = foo6_get0 (h, b_seg);
+ /* break 12 */
+ vint32mf2_t res_b_seg1 = foo6_get1 (h, b_seg);
+ /* break 13 */
+
+ free (rs1_mask);
+ free (addr);
+ free (rs1);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/riscv-vector-abi.exp b/gdb/testsuite/gdb.arch/riscv-vector-abi.exp
new file mode 100644
index 00000000000..10c379c6097
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vector-abi.exp
@@ -0,0 +1,247 @@
+# Copyright 2026 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+load_lib riscv64-rvv-lib.exp
+
+set get_vl_called_times 0
+
+proc get_vl {} {
+ global hex
+ global decimal
+ global gdb_prompt
+ global gdb_test_name
+ global get_vl_called_times
+
+ set vl 0x0
+
+ gdb_test_multiple "info registers \$vl" "$get_vl_called_times call of get_vl()" {
+ -re "^info registers\[^\r\n\]+\r\n" {
+ exp_continue
+ }
+
+ -re "^vl\\s+(${hex})\\s+(${decimal})\r\n" {
+ set vl $expect_out(2,string)
+ exp_continue
+ }
+
+ -re "^$gdb_prompt $" {
+ pass $gdb_test_name
+ }
+ }
+
+ set get_vl_called_times [expr {$get_vl_called_times + 1}]
+
+ return $vl
+}
+
+proc generate_sequence { start step count } {
+ if {$step == 0 && $count > 8} {
+ return "$start <repeats $count times>"
+ }
+
+ set res "$start"
+ set count [expr {$count - 1}]
+
+ for {set i 0} {$i < $count} {incr i} {
+ set start [expr {$start + $step}]
+ set res "${res}, $start"
+ }
+
+ return $res
+}
+
+proc test_print_with_rvv_state_check { command regexp } {
+ set vector_state_before_call [capture_command_output "info vector" ""]
+
+ gdb_test $command $regexp
+
+ set vector_state_after_call [capture_command_output "info vector" ""]
+ if ![string compare $vector_state_before_call $vector_state_after_call] {
+ pass "vector state was saved/restored correctly during $command"
+ } else {
+ fail "vector state wasn't saved/restored correctly durring $command"
+ }
+}
+
+if {![riscv_support_rvv]} {
+ unsupported "RVV unsupported"
+ return
+}
+
+if {![riscv_support_rvv_intrinsic]} {
+ unsupported "RVV intrinsic unsupported"
+ return
+}
+
+standard_testfile
+
+set compile_flags {"debug"}
+lappend compile_flags "additional_flags=-march=rv64gcv"
+
+# First, we figure out VLENB value to set correct vector extension to march
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile $compile_flags]} {
+ return -1
+}
+
+if {![runto_main]} {
+ return -1
+}
+
+gdb_breakpoint "$srcfile:[gdb_get_line_number "break 2"]"
+gdb_continue_to_breakpoint "preparing stage"
+set vlenb [riscvlib_rvv_get_csr vlenb "$testfile"]
+
+set compile_flags {"debug"}
+if {$vlenb >= 16} {
+ lappend compile_flags "additional_flags=-march=rv64gcv"
+} elseif {$vlenb >= 8} {
+ lappend compile_flags "additional_flags=-march=rv64gc_zve64d"
+} else {
+ unsupported "Unsupported VLENB value: $vlenb"
+ return
+}
+
+# Here is real test started
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile $compile_flags]} {
+ return -1
+}
+
+if {![runto_main]} {
+ return -1
+}
+
+for {set i 2} {$i <= 13} {incr i} {
+ gdb_breakpoint "$srcfile:[gdb_get_line_number "break $i"]"
+}
+
+gdb_continue_to_breakpoint "break 2"
+
+set vl [get_vl]
+
+gdb_test "print a" "\\{[generate_sequence 42 0 $vl]\\}"
+gdb_test "print b" "\\{[generate_sequence 43 0 $vl]\\}"
+gdb_test "print c" "\\{[generate_sequence 44 0 $vl]\\}"
+gdb_test "print res" "\\{[generate_sequence 129 0 $vl]\\}"
+test_print_with_rvv_state_check "print foo(a, b, c, n)" "\\{[generate_sequence 129 0 $vl]\\}"
+
+gdb_continue_to_breakpoint "break 3"
+
+set vl [get_vl]
+
+gdb_test "print g" "\\{[generate_sequence 48 0 $vl]\\}"
+gdb_test "print h" "\\{[generate_sequence 49 0 $vl]\\}"
+
+gdb_test "print res_1" "\\{[generate_sequence 97 0 $vl]\\}"
+test_print_with_rvv_state_check "print foo1(g, h, n)" "\\{[generate_sequence 97 0 $vl]\\}"
+
+gdb_test "print res_2" "\\{[generate_sequence 97 0 $vl]\\}"
+test_print_with_rvv_state_check "print foo2(h, g, n)" "\\{[generate_sequence 97 0 $vl]\\}"
+
+gdb_continue_to_breakpoint "break 4"
+
+set vl [get_vl]
+
+gdb_test "print big1" "\\{[generate_sequence 50 0 $vl]\\}"
+gdb_test "print big2" "\\{[generate_sequence 51 0 $vl]\\}"
+gdb_test "print big3" "\\{[generate_sequence 52 0 $vl]\\}"
+gdb_test "print big_res" "\\{[generate_sequence 153 0 $vl]\\}"
+test_print_with_rvv_state_check "print foo3(big1, big2, big3, n)" "\\{[generate_sequence 153 0 $vl]\\}"
+
+gdb_continue_to_breakpoint "break 5"
+
+set vl [get_vl]
+set repeat_num [expr {$vl / 8 - 1}]
+
+set pattern_part "101, -?\\d+, 101, -?\\d+, -?\\d+, 101, -?\\d+, 101"
+set pattern "\\{$pattern_part"
+for {set i 0} {$i < $repeat_num} {incr i} {
+ set pattern "$pattern, $pattern_part"
+}
+set pattern "$pattern\\}"
+
+gdb_test "print masked_sum" $pattern
+test_print_with_rvv_state_check "print foo4(big1, big2, mask, mask, n)" $pattern
+
+gdb_continue_to_breakpoint "break 6"
+
+set vl [get_vl]
+
+set pattern "\\{[generate_sequence 0 8 $vl]\\}"
+
+gdb_test "print rs2" $pattern
+
+gdb_continue_to_breakpoint "break 7"
+
+set vl [get_vl]
+
+set pattern [riscvlib_rvv_tuple_pattern [list \
+ "\\{[generate_sequence 0 2 $vl]\\}" \
+ "\\{[generate_sequence 1 2 $vl]\\}"]]
+
+gdb_test "print a_seg" $pattern
+
+gdb_continue_to_breakpoint "break 8"
+
+set vl [get_vl]
+
+set pattern "= \\{[generate_sequence 0 2 $vl].*\\}"
+
+gdb_test "print res_a_seg0" $pattern
+test_print_with_rvv_state_check "print foo5_get0(h, a_seg)" $pattern
+
+gdb_continue_to_breakpoint "break 9"
+
+set vl [get_vl]
+
+set pattern "= \\{[generate_sequence 1 2 $vl].*\\}"
+
+gdb_test "print res_a_seg1" $pattern
+test_print_with_rvv_state_check "print foo5_get1(h, a_seg)" $pattern
+
+gdb_continue_to_breakpoint "break 10"
+
+set vl [get_vl]
+
+set pattern "\\{[generate_sequence 0 8 $vl]\\}"
+
+gdb_test "print rs2_2" $pattern
+
+gdb_continue_to_breakpoint "break 11"
+
+set vl [get_vl]
+
+set pattern [riscvlib_rvv_tuple_pattern [list \
+ "\\{[generate_sequence 0 2 $vl]\\}" \
+ "\\{[generate_sequence 1 2 $vl]\\}"]]
+
+gdb_test "print b_seg" $pattern
+
+gdb_continue_to_breakpoint "break 12"
+
+set vl [get_vl]
+
+set pattern "= \\{[generate_sequence 0 2 $vl].*\\}"
+
+gdb_test "print res_b_seg0" $pattern
+test_print_with_rvv_state_check "print foo6_get0(h, b_seg)" $pattern
+
+gdb_continue_to_breakpoint "break 13"
+
+set vl [get_vl]
+
+set pattern "= \\{[generate_sequence 1 2 $vl].*\\}"
+
+gdb_test "print res_b_seg1" $pattern
+test_print_with_rvv_state_check "print foo6_get1(h, b_seg)" $pattern
diff --git a/gdb/testsuite/gdb.arch/riscv-vu-availability.c b/gdb/testsuite/gdb.arch/riscv-vu-availability.c
new file mode 100644
index 00000000000..7321cf251f8
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vu-availability.c
@@ -0,0 +1,67 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2026 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+asm (".option arch, +v\n");
+
+unsigned
+do_vlenb_read ()
+{
+ unsigned vlenb;
+ asm volatile ("csrr %[vlenb], vlenb" : [vlenb] "=r"(vlenb) : :);
+ return vlenb;
+}
+
+unsigned
+do_vsetvli ()
+{
+ unsigned vl;
+ asm volatile ("vsetvli %[new_vl], x0, e8, m1, ta, ma"
+ : [new_vl] "=r"(vl)
+ :
+ :);
+ return vl;
+}
+
+#ifdef READ_VLENB_BEFORE_MAIN
+unsigned VLENB = do_vlenb_read ();
+#endif // READ_VLENB_BEFORE_MAIN
+
+#ifdef SET_VSETVLI_BEFORE_MAIN
+unsigned VL = do_vsetvli ();
+#endif // SET_VSETVLI_BEFORE_MAIN
+
+int STORAGE[64];
+
+void
+do_vector_stuff ()
+{
+ do_vsetvli ();
+ asm volatile ("vadd.vi v1, v1, 0x1");
+ asm volatile ("vadd.vi v2, v1, 0x2");
+ asm volatile ("vs1r.v v1, (%0)"
+ :
+ : "r"(STORAGE)
+ : "memory"); /* pre_vect_mem */
+ asm volatile ("vl1re8.v v2, (%0)" : : "r"(STORAGE) : "memory");
+}
+
+int
+main ()
+{
+ do_vector_stuff ();
+ return 0; /* post_vector_op */
+}
diff --git a/gdb/testsuite/gdb.arch/riscv-vu-availability.exp b/gdb/testsuite/gdb.arch/riscv-vu-availability.exp
new file mode 100644
index 00000000000..c96c1235647
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vu-availability.exp
@@ -0,0 +1,72 @@
+# Copyright 2026 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+require {istarget "riscv*-*-*"}
+
+if {![riscv_support_rvv]} {
+ unsupported "RVV unsupported"
+ return
+}
+
+standard_testfile
+load_lib riscv64-rvv-lib.exp
+
+proc initialize_vu_availability_test {extra_args } {
+ global testfile
+ global srcfile
+
+ set compile_flags {}
+ lappend compile_flags debug
+ lappend compile_flags c++
+ lappend compile_flags "additional_flags=-march=rv64gc ${extra_args}"
+
+ if {[prepare_for_testing "failed to prepare" $testfile $srcfile $compile_flags]} {
+ return -1
+ }
+
+ if {![runto_main]} {
+ return -1
+ }
+}
+
+proc test_unavailable_regs { extra_args } {
+ initialize_vu_availability_test ${extra_args}
+ gdb_test "print \$vtype" "= <unavailable>" "test vtype unavailable ${extra_args}"
+ gdb_test "print \$vcsr" "= <unavailable>" "test vcsr unavailable ${extra_args}"
+ gdb_test "print \$vl" "= <unavailable>" "test vl unavailable ${extra_args}"
+ gdb_test "print \$vstart" "= <unavailable>" "test vstart unavailable ${extra_args}"
+ gdb_test "print \$vlenb" "= <unavailable>" "test vlenb unavailable ${extra_args}"
+ for {set i 0} {$i < 32} {incr i} {
+ gdb_test "print \$v${i}" "= <unavailable>" "test v${i} unavailable ${extra_args}"
+ }
+}
+
+proc test_available_regs { extra_args } {
+ global testfile
+ initialize_vu_availability_test ${extra_args}
+ set VLENB [riscvlib_rvv_get_csr vlenb "$testfile"]
+ gdb_test "print \$vtype" "= 192" "test vtype available ${extra_args}"
+ gdb_test "print \$vcsr" "= 0" "test vcsr available ${extra_args}"
+ gdb_test "print \$vl" "= $VLENB" "test vl available ${extra_args}"
+ gdb_test "print \$vstart" "= 0" "test vstart available ${extra_args}"
+ gdb_test "print \$vlenb" "= $VLENB" "test vlenb available ${extra_args}"
+ for {set i 0} {$i < 32} {incr i} {
+ gdb_test "print \$v${i}" [riscvlib_rvv_vreg_zero_pattern $VLENB] "test v${i} available ${extra_args}"
+ }
+}
+
+test_unavailable_regs "-DREAD_VLENB_BEFORE_MAIN"
+test_unavailable_regs ""
+test_available_regs "-DSET_VSETVLI_BEFORE_MAIN"
diff --git a/gdb/testsuite/gdb.arch/riscv-vu-consitency-checks.c b/gdb/testsuite/gdb.arch/riscv-vu-consitency-checks.c
new file mode 100644
index 00000000000..918ceedc2c6
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vu-consitency-checks.c
@@ -0,0 +1,79 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2026 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+asm (".option arch, +v\n");
+
+#include <stdlib.h>
+#include <limits.h>
+#include <stdint.h>
+
+unsigned
+do_vlenb_read ()
+{
+ unsigned vlenb;
+ asm volatile ("csrr %[vlenb], vlenb" : [vlenb] "=r"(vlenb) : :);
+ return vlenb;
+}
+
+void
+reset_vu ()
+{
+ unsigned vl;
+ asm volatile ("vsetvli %[new_vl], x0, e8, m8, ta, ma"
+ : [new_vl] "=r"(vl)
+ :
+ :);
+ asm volatile ("vxor.vv v0, v0, v0\n"
+ "vxor.vv v8, v8, v8\n"
+ "vxor.vv v16, v16, v16\n"
+ "vxor.vv v24, v24, v24\n"
+ "csrrci zero, vxrm, 3\n"
+ "csrrci zero, vxsat, 1\n");
+ asm volatile ("vsetvli %[new_vl], x0, e8, m1, tu, mu"
+ : [new_vl] "=r"(vl)
+ :
+ :);
+ asm volatile ("nop"); /* vu_reset_end */
+}
+
+void
+do_workload ()
+{
+ unsigned long long app_vtype;
+ unsigned app_vl;
+ unsigned app_vlenb;
+ asm volatile ("csrr %[vtype], vtype\n" : [vtype] "=r"(app_vtype) : :);
+ asm volatile ("csrr %[vl], vl\n"
+ : [vl] "=r"(app_vl) /* vect_test_vtype_read */
+ :
+ :);
+ asm volatile ("csrr %[vlenb], vlenb\n" : [vlenb] "=r"(app_vlenb) : :);
+ asm volatile ("vxor.vv v24, v16, v8\n" : : :);
+ asm volatile ("nop"); /* workload_end */
+}
+
+int
+main ()
+{
+ unsigned vlenb_value = do_vlenb_read ();
+ (void) vlenb_value;
+ reset_vu ();
+ /* vect_test_start */
+ for (int i = 0; i < 777; ++i)
+ do_workload ();
+ return 0; /* vect_test_end */
+}
diff --git a/gdb/testsuite/gdb.arch/riscv-vu-consitency-checks.exp b/gdb/testsuite/gdb.arch/riscv-vu-consitency-checks.exp
new file mode 100644
index 00000000000..9d0e8e81ec7
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vu-consitency-checks.exp
@@ -0,0 +1,156 @@
+# Copyright 2026 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+require {istarget "riscv*-*-*"}
+
+if {![riscv_support_rvv]} {
+ unsupported "RVV unsupported"
+ return
+}
+
+standard_testfile
+load_lib riscv64-rvv-lib.exp
+
+proc test_vu_consistency_vl_overflow {VLENB} {
+ set the_proc [lindex [info level 0] 0]
+
+ gdb_continue_to_breakpoint "$the_proc: start"
+ set vtype_val [riscvlib_rvv_get_vtype_val 1 e8 tu mu]
+ set vl_val [riscvlib_get_vlmax $VLENB 1 e8]
+ gdb_test "print app_vtype" "= $vtype_val" "$the_proc: app vtype"
+ gdb_test "print app_vl" "= $vl_val" "$the_proc: app vl"
+ gdb_test "print app_vlenb" "= $VLENB" "$the_proc: app vlenb"
+ set large_vl 9999
+ gdb_test_no_output "set \$vl = $large_vl" "$the_proc: set illegal large vl"
+
+ gdb_continue_to_breakpoint "$the_proc: vl illegal value is ignored"
+ gdb_test "print app_vtype" "= $vtype_val" "$the_proc: app vtype - after vl update"
+ gdb_test "print app_vl" "= $vl_val" "$the_proc: app vl - after vl update"
+ gdb_test "print app_vlenb" "= $VLENB" "$the_proc: app vlenb - after vl update"
+ gdb_test "print \$vl" "= $vl_val" "$the_proc: ptraced vl - after vl update"
+}
+
+proc test_vu_coherent_vl_lmul_downgrade {VLENB} {
+ set the_proc [lindex [info level 0] 0]
+
+ gdb_continue_to_breakpoint "$the_proc: start"
+ set vtype_val [riscvlib_rvv_get_vtype_val 8 e8 tu mu]
+ gdb_test_no_output "set \$vtype = $vtype_val" "$the_proc: set \$vtype = $vtype_val value"
+ set vl_val [riscvlib_get_vlmax $VLENB 8 e8]
+ gdb_test_no_output "set \$vl = $vl_val" "$the_proc: set \$vl = $vl_val value"
+ gdb_continue_to_breakpoint "$the_proc: run with updated vtype and vl"
+
+ gdb_test "print app_vtype" "= $vtype_val" "$the_proc: app vtype - after vtype LMUL 8 update"
+ gdb_test "print app_vl" "= $vl_val" "$the_proc: app vl - after vl LMUL 8 update"
+ gdb_test "print app_vlenb" "= $VLENB" "$the_proc: app vlenb - after LMUL 8 update"
+ gdb_test "print \$vl" "= $vl_val" "$the_proc: ptraced vl - VLENB * 8"
+ gdb_test "print \$vtype" "= $vtype_val" "$the_proc: ptraced vtype - 3"
+
+ gdb_continue_to_breakpoint "$the_proc: going to switch LMUL back to 1"
+ # We need to downgrade vl here first, because large vl + small vtype is unavailable configuration
+ set vl_val [riscvlib_get_vlmax $VLENB 1 e8]
+ gdb_test_no_output "set \$vl = $vl_val" "$the_proc: set \$vl = $vl_val value"
+ set vtype_val [riscvlib_rvv_get_vtype_val 1 e8 tu mu]
+ gdb_test_no_output "set \$vtype = $vtype_val" "$the_proc: set \$vtype = $vtype_val value"
+
+ gdb_continue_to_breakpoint "$the_proc: LMUL should be 1"
+ gdb_test "print app_vtype" "= $vtype_val" "$the_proc: app vtype - after LMUL 1 update"
+ gdb_test "print app_vl" "= $vl_val" "$the_proc: app vl - after LMUL 1 update"
+ gdb_test "print app_vlenb" "= $VLENB" "$the_proc: app vlenb - after LMUL 1 update"
+ gdb_test "print \$vl" "= $vl_val" "$the_proc: ptraced vl - after LMUL 1 update"
+ gdb_test "print \$vtype" "= $vtype_val" "$the_proc: ptraced vtype - after LMUL 1 update"
+}
+
+proc test_vu_coherent_non_zero_vstart {VLENB} {
+ set the_proc [lindex [info level 0] 0]
+ gdb_continue_to_breakpoint "$the_proc: messing up vstart"
+ gdb_test_no_output "set \$vstart = 8"
+
+ gdb_continue_to_breakpoint "$the_proc: vstart was 8"
+ gdb_test "print \$vstart" "= 0" "$the_proc: ptraced vstart - after vstart update"
+}
+
+proc test_vu_consistency_incorrect_vtype {VLENB} {
+ global srcfile
+ set the_proc [lindex [info level 0] 0]
+ if {$VLENB >= 64} {
+ untested "$the_proc: VLENB must be less than 64"
+ return
+ }
+
+ set legal_vtype [riscvlib_rvv_get_vtype_val 1 e8 tu mu]
+ set legal_vl [riscvlib_get_vlmax $VLENB 1 e8]
+ gdb_test_no_output "set \$vtype = $legal_vtype" "$the_proc: set \$vtype = $legal_vtype value"
+ gdb_test_no_output "set \$vl = $legal_vl" "$the_proc: set \$vl = $legal_vl value"
+ gdb_continue_to_breakpoint "$the_proc: setting SEW to 8 and LMUL to 1"
+ gdb_test "print app_vtype" "= $legal_vtype" "$the_proc: app_vtype - legal"
+ gdb_test "print app_vl" "= $legal_vl" "$the_proc: app vl - legal"
+ gdb_test "print app_vlenb" "= $VLENB" "$the_proc: app vlenb - legal"
+ gdb_test "print \$vl" "= $legal_vl" "$the_proc: ptraced vl - legal"
+ gdb_test "print \$vtype" "= $legal_vtype" "$the_proc: ptraced vtype - legal"
+
+ gdb_continue_to_breakpoint "$the_proc: setting SEW to 64 and LMUL to 1/8"
+ set incorrect_vtype [riscvlib_rvv_get_vtype_val 1/8 e64 tu mu]
+ gdb_test_no_output "set \$vtype = $incorrect_vtype" "$the_proc: set \$vtype = $incorrect_vtype value"
+ gdb_test "stepi" ".*" "$the_proc: stepi after incorrect"
+ gdb_test "print \$vtype" "= $legal_vtype" "$the_proc: ptraced vtype - after setting illegal mode"
+ gdb_continue_to_breakpoint "$the_proc: after setting illegal mode"
+ gdb_test "print app_vtype" "= $legal_vtype" "$the_proc: app_vtype - still legal"
+ gdb_test "print app_vl" "= $legal_vl" "$the_proc: app vl - still legal"
+ gdb_test "print app_vlenb" "= $VLENB" "$the_proc: app vlenb - still legal"
+ gdb_test "print \$vl" "= $legal_vl" "$the_proc: ptraced vl - still legal"
+ gdb_test "print \$vtype" "= $legal_vtype" "$the_proc: ptraced vtype - still legal"
+}
+
+proc test_vu_do_consistency_test {VLENB} {
+ global srcfile
+ gdb_breakpoint "$srcfile:[gdb_get_line_number workload_end]"
+
+ gdb_continue_to_breakpoint "warm up"
+
+ test_vu_consistency_vl_overflow $VLENB
+ test_vu_coherent_vl_lmul_downgrade $VLENB
+ test_vu_coherent_non_zero_vstart $VLENB
+ test_vu_consistency_incorrect_vtype $VLENB
+}
+
+proc prepare_vu_consistency_test {} {
+ global testfile
+ global srcfile
+
+ set compile_flags {}
+ lappend compile_flags debug
+ lappend compile_flags "additional_flags=-march=rv64gc"
+
+ if {[prepare_for_testing "failed to prepare" $testfile $srcfile $compile_flags]} {
+ return -1
+ }
+
+ if {![runto_main]} {
+ return -1
+ }
+
+ gdb_breakpoint "$srcfile:[gdb_get_line_number vect_test_start]"
+ gdb_continue_to_breakpoint "vect_test_start"
+
+ return 0
+}
+
+if {[prepare_vu_consistency_test]} {
+ untested "could not initialize"
+ return -1
+}
+set vlenb [riscvlib_rvv_get_csr vlenb "$testfile"]
+test_vu_do_consistency_test $vlenb
diff --git a/gdb/testsuite/gdb.arch/riscv-vu-ctx-print.c b/gdb/testsuite/gdb.arch/riscv-vu-ctx-print.c
new file mode 100644
index 00000000000..a9b39a22606
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vu-ctx-print.c
@@ -0,0 +1,106 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2026 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <vector>
+
+asm (".option arch, +v\n");
+
+enum VLMUL
+{
+ LMUL1 = 0,
+ LMUL2 = 1,
+ LMUL4 = 2,
+ LMUL8 = 3,
+ LMUL_F8 = 5,
+ LMUL_F4 = 6,
+ LMUL_F2 = 7
+};
+
+enum SEW
+{
+ SEW8 = 0,
+ SEW16 = 1,
+ SEW32 = 2,
+ SEW64 = 3,
+};
+
+unsigned
+do_vsetvli ()
+{
+ unsigned vl;
+ asm volatile ("vsetvli %[new_vl], x0, e8, m1, ta, ma"
+ : [new_vl] "=r"(vl)
+ :
+ :);
+ return vl;
+}
+
+unsigned
+do_vsetv (unsigned vl, VLMUL vlmul, SEW vsew, unsigned vta, unsigned vma)
+{
+ unsigned vtype = (unsigned) vlmul | ((unsigned) vsew << 3) | (vta << 6)
+ | (vma << 7);
+ asm volatile ("vsetvl %[new_vl], %[new_vl], %[vtype]"
+ : [new_vl] "+r"(vl)
+ : [vtype] "r"(vtype)
+ :);
+ return vl; /* vsetvl_done */
+}
+
+int STORAGE[64];
+
+void
+do_vector_stuff ()
+{
+ std::vector<VLMUL> vlmul = {
+ VLMUL::LMUL1, VLMUL::LMUL2, VLMUL::LMUL4, VLMUL::LMUL8,
+ VLMUL::LMUL_F8, VLMUL::LMUL_F4, VLMUL::LMUL_F2,
+ };
+ std::vector<SEW> vsew = {
+ SEW::SEW8,
+ SEW::SEW16,
+ SEW::SEW32,
+ SEW::SEW64,
+ };
+ for (auto vlmul : vlmul)
+ for (auto sew : vsew)
+ for (int vta = 0; vta < 2; ++vta)
+ for (int vma = 0; vma < 2; ++vma)
+ for (int vl = 1; vl < 3; ++vl)
+ do_vsetv (vl, vlmul, sew, vta, vma);
+
+ asm volatile ("csrw vxrm, %[rnd_m]" : : [rnd_m] "i"(0) :);
+ asm volatile ("csrw vxrm, %[rnd_m]" : : [rnd_m] "i"(1) :); /* vxrm_0 */
+ asm volatile ("csrw vxrm, %[rnd_m]" : : [rnd_m] "i"(2) :); /* vxrm_1 */
+ asm volatile ("csrw vxrm, %[rnd_m]" : : [rnd_m] "i"(3) :); /* vxrm_2 */
+ asm volatile ("csrw vxsat, %[vxsat]" : : [vxsat] "i"(1) :); /* vxrm_3 */
+ asm volatile ("csrw vxrm, %[rnd_m]" : : [rnd_m] "i"(0) :); /* vxrm_0_again */
+ unsigned vtype = -1;
+ unsigned vl = -1;
+ asm volatile ("vsetvl %[new_vl], %[new_vl], %[vtype]"
+ : [new_vl] "+r"(vl), [vtype] "=r"(vtype)
+ :
+ :); /* vcsr_done */
+}
+
+int
+main ()
+{
+ do_vsetvli ();
+ do_vector_stuff (); /* rvv_initialized */
+ return 0; /* do_vector_stuff_done */
+}
diff --git a/gdb/testsuite/gdb.arch/riscv-vu-ctx-print.exp b/gdb/testsuite/gdb.arch/riscv-vu-ctx-print.exp
new file mode 100644
index 00000000000..4d32c3a03a9
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vu-ctx-print.exp
@@ -0,0 +1,107 @@
+# Copyright 2026 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+require {istarget "riscv*-*-*"}
+
+if {![riscv_support_rvv]} {
+ unsupported "RVV unsupported"
+ return
+}
+
+standard_testfile
+load_lib riscv64-rvv-lib.exp
+
+proc test_vu_ctx_printouts {VLENB} {
+ global testfile
+ global srcfile
+ global hex
+
+ array set vlmul { 0 1 1 2 2 4 3 8 7 1/2 6 1/4 5 1/8 }
+ array set vsew { 0 e8 1 e16 2 e32 3 e64 }
+ array set vta { 0 tu 1 ta }
+ array set vma { 0 mu 1 ma }
+ gdb_breakpoint "$srcfile:[gdb_get_line_number vsetvl_done]"
+
+ foreach lmul [lsort -integer [array names vlmul]] {
+ foreach sew [lsort -integer [array names vsew]] {
+ foreach ta [lsort -integer [array names vta]] {
+ foreach ma [lsort -integer [array names vma]] {
+ foreach vl {1 2} {
+ set slmul $vlmul($lmul)
+ set ssew $vsew($sew)
+ set sta $vta($ta)
+ set sma $vma($ma)
+ set case_id "vlmul: $lmul, sew: $sew, ta: $ta, ma: $ma, vl: $vl"
+ gdb_continue_to_breakpoint "vsetvl_done lmul / $case_id"
+
+ if {![riscvlib_is_vlmul_vsew_legal $VLENB $slmul $ssew]} {
+ set vtype_pattern "vill:1"
+ } else {
+ set vtype_pattern "$hex\tLMUL:$lmul \\($slmul\\) SEW:$sew \\($ssew\\) vta:$ta \\($sta\\) vma:$ma \\($sma\\) vill:0"
+ }
+ gdb_test "info reg vtype" "${vtype_pattern}" "info reg vtype: $case_id"
+ set fvl [riscvlib_get_allowed_vl $VLENB $slmul $ssew $vl]
+ gdb_test "info reg vl" "^vl\\s+[format 0x%x $fvl]\t$fvl" "info reg vl: $case_id, fvl: $fvl"
+ }
+ }
+ }
+ }
+ }
+
+ foreach vxrm {0 1 2 3} {
+ gdb_breakpoint "$srcfile:[gdb_get_line_number vxrm_$vxrm]"
+ gdb_continue_to_breakpoint "vxrm_$vxrm"
+ set vcsr_value_hex [format 0x%x [expr { ($vxrm << 1) }]]
+ gdb_test "info reg vcsr" "^vcsr\\s+$vcsr_value_hex\tVXSAT:0 VXRM:$vxrm" "info reg vcsr: vxrm_$vxrm"
+ }
+
+ gdb_breakpoint "$srcfile:[gdb_get_line_number vxrm_0_again]"
+ gdb_continue_to_breakpoint "vxrm_0_again"
+ gdb_test "info reg vcsr" "^vcsr\\s+0x7\tVXSAT:1 VXRM:3" "info reg vcsr: vxsat_1"
+
+ gdb_breakpoint "$srcfile:[gdb_get_line_number vcsr_done]"
+ gdb_continue_to_breakpoint "vcsr_done"
+ gdb_test "info reg vcsr" "^vcsr\\s+0x1\tVXSAT:1 VXRM:0" "info reg vcsr: vxsat_1_vxrm0"
+}
+
+proc prepare_vu_printout_test {} {
+ global testfile
+ global srcfile
+
+ set compile_flags {}
+ lappend compile_flags debug
+ lappend compile_flags c++
+ lappend compile_flags "additional_flags=-march=rv64gc"
+
+ if {[prepare_for_testing "failed to prepare" $testfile $srcfile $compile_flags]} {
+ return -1
+ }
+
+ if {![runto_main]} {
+ return -1
+ }
+
+ return 0
+}
+
+if {[prepare_vu_printout_test]} {
+ untested "could not initialize"
+ return -1
+}
+gdb_breakpoint "$srcfile:[gdb_get_line_number rvv_initialized]"
+gdb_continue_to_breakpoint "rvv_initialized"
+set vlenb [riscvlib_rvv_get_csr vlenb "$testfile"]
+
+test_vu_ctx_printouts $vlenb
diff --git a/gdb/testsuite/gdb.arch/riscv-vu-printout.c b/gdb/testsuite/gdb.arch/riscv-vu-printout.c
new file mode 100644
index 00000000000..30b6680a757
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vu-printout.c
@@ -0,0 +1,69 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2026 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <limits.h>
+
+asm (".option arch, +v\n");
+
+unsigned
+do_vlenb_read ()
+{
+ unsigned vlenb;
+ asm volatile ("csrr %[vlenb], vlenb" : [vlenb] "=r"(vlenb) : :);
+ return vlenb;
+}
+
+unsigned
+do_vsetvli ()
+{
+ unsigned vl;
+ asm volatile ("vsetvli %[new_vl], x0, e8, m8, tu, mu"
+ : [new_vl] "=r"(vl)
+ :
+ :);
+ return vl;
+}
+
+char *STORAGE;
+
+void
+do_vector_stuff ()
+{
+ unsigned vlenb_value = do_vlenb_read ();
+ STORAGE = (char *) calloc (1, vlenb_value * CHAR_BIT);
+ do_vsetvli ();
+ asm volatile ("vxor.vv v0, v0, v0");
+ asm volatile ("vxor.vv v8, v8, v8");
+ asm volatile ("vxor.vv v16, v16, v16");
+ asm volatile ("vxor.vv v24, v24, v24");
+ asm volatile ("vsetvli t0, x0, e8, m1, tu, mu" : : : "t0");
+ asm volatile ("vadd.vi v1, v1, 0x1");
+ asm volatile ("vadd.vi v2, v1, 0x2");
+ asm volatile ("vs1r.v v1, (%0)"
+ :
+ : "r"(STORAGE)
+ : "memory"); /* pre_vect_mem */
+ asm volatile ("vl1re8.v v2, (%0)" : : "r"(STORAGE) : "memory");
+}
+
+int
+main ()
+{
+ do_vector_stuff ();
+ return 0; /* post_vector_op */
+}
diff --git a/gdb/testsuite/gdb.arch/riscv-vu-printout.exp b/gdb/testsuite/gdb.arch/riscv-vu-printout.exp
new file mode 100644
index 00000000000..0ca37878945
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vu-printout.exp
@@ -0,0 +1,92 @@
+# Copyright 2026 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+require {istarget "riscv*-*-*"}
+
+if {![riscv_support_rvv]} {
+ unsupported "RVV unsupported"
+ return
+}
+
+standard_testfile
+load_lib riscv64-rvv-lib.exp
+
+proc test_vu_printouts {VLENB} {
+ global srcfile
+
+ set vtype_pattern "0x0\tLMUL:0 \\(1\\) SEW:0 \\(e8\\) vta:0 \\(tu\\) vma:0 \\(mu\\) vill:0"
+ gdb_test "info reg vtype" "${vtype_pattern}" "printout info reg vtype"
+ gdb_test "info reg vcsr" "0x0\tVXSAT:0 VXRM:0" "printout info reg vcsr"
+ gdb_test "info reg vl" "[format 0x%x $VLENB]\t$VLENB" "printout info reg vl"
+ gdb_test "info reg vstart" "0x0\t0" "printout info reg vstart"
+ gdb_test "info reg vlenb" "[format 0x%x $VLENB]\t$VLENB" "printout info reg vlenb"
+
+ set zero_pattern [riscvlib_rvv_vreg_zero_pattern $VLENB]
+ gdb_test "print \$v0" ${zero_pattern} "printout print v0"
+ gdb_test "print \$v1" [riscvlib_rvv_vreg_1_pattern $VLENB] "printout print v1"
+ gdb_test "print \$v2" [riscvlib_rvv_vreg_3_pattern $VLENB] "printout print v2"
+ for {set i 3} {$i < 32} {incr i} {
+ gdb_test "print \$v${i}" ${zero_pattern} "printout print v${i}"
+ }
+
+ set vregs [capture_command_output "info registers vector" ""]
+ foreach {- regname} [regexp -all -inline -line {^(\w+)\s+} $vregs] {
+ incr vreg_arr($regname)
+ }
+ set expected_list { vtype vcsr vl vstart vlenb }
+ for {set i 0 } { $i < 32 } { incr i } {
+ lappend expected_list v$i
+ }
+ set s_expc_list [lsort $expected_list]
+ set s_vreg_list [lsort [array names vreg_arr]]
+ if {![string equal $s_expc_list $s_vreg_list]} {
+ fail "info registers vector (contents)"
+ }
+ foreach reg $expected_list {
+ if { $vreg_arr($reg) != 1 } {
+ fail "info registers vector has duplicated $reg"
+ } else {
+ pass "info register vector has $reg"
+ }
+ }
+}
+
+proc prepare_vu_printout_test {} {
+ global testfile
+ global srcfile
+
+ set compile_flags {}
+ lappend compile_flags debug
+ lappend compile_flags "additional_flags=-march=rv64gc"
+
+ if {[prepare_for_testing "failed to prepare" $testfile $srcfile $compile_flags]} {
+ return -1
+ }
+
+ if {![runto_main]} {
+ return -1
+ }
+
+ gdb_breakpoint "$srcfile:[gdb_get_line_number pre_vect_mem]"
+ gdb_continue_to_breakpoint "pre_vect_mem"
+ return 0
+}
+
+if {[prepare_vu_printout_test]} {
+ untested "could not initialize"
+ return -1
+}
+set vlenb [riscvlib_rvv_get_csr vlenb "$testfile"]
+test_vu_printouts $vlenb
diff --git a/gdb/testsuite/gdb.arch/riscv-vu-rvv-unsupported.c b/gdb/testsuite/gdb.arch/riscv-vu-rvv-unsupported.c
new file mode 100644
index 00000000000..70e934ad6ca
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vu-rvv-unsupported.c
@@ -0,0 +1,23 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2026 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+int
+main ()
+{
+ int a = 42;
+ return 0; /* break 2 */
+}
diff --git a/gdb/testsuite/gdb.arch/riscv-vu-rvv-unsupported.exp b/gdb/testsuite/gdb.arch/riscv-vu-rvv-unsupported.exp
new file mode 100644
index 00000000000..57a35df54c1
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vu-rvv-unsupported.exp
@@ -0,0 +1,46 @@
+# Copyright 2026 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+require {istarget "riscv*-*-*"}
+
+if {[riscv_support_rvv]} {
+ unsupported "need to run on targets without RVV support"
+ return
+}
+
+standard_testfile
+
+set compile_flags {"debug"}
+lappend compile_flags "additional_flags=-march=rv64gcv"
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile $compile_flags]} {
+ return -1
+}
+
+if {![runto_main]} {
+ return -1
+}
+
+gdb_breakpoint "$srcfile:[gdb_get_line_number "break 2"]"
+gdb_continue_to_breakpoint "break 2"
+
+gdb_test "print a" " = 42"
+
+set a0_val 42
+set a0_hex_val 0x[format %x $a0_val]
+gdb_test_no_output "set \$a0 = $a0_val"
+gdb_test "info reg a0" "a0\[ \t\]+$a0_hex_val\[ \t\]+$a0_val"
+
+gdb_test "info reg v0" "Invalid register `v0'"
diff --git a/gdb/testsuite/gdb.arch/riscv-vu-rwr.c b/gdb/testsuite/gdb.arch/riscv-vu-rwr.c
new file mode 100644
index 00000000000..9ba09d60f1f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vu-rwr.c
@@ -0,0 +1,62 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2026 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+asm (".option arch, +v\n");
+
+#include <stdlib.h>
+#include <limits.h>
+
+unsigned
+do_vlenb_read ()
+{
+ unsigned vlenb;
+ asm volatile ("csrr %[vlenb], vlenb" : [vlenb] "=r"(vlenb) : :);
+ return vlenb;
+}
+
+void
+reset_vu ()
+{
+ unsigned vl;
+ asm volatile ("vsetvli %[new_vl], x0, e8, m8, ta, ma"
+ : [new_vl] "=r"(vl)
+ :
+ :);
+ asm volatile ("vxor.vv v0, v0, v0\n"
+ "vxor.vv v8, v8, v8\n"
+ "vxor.vv v16, v16, v16\n"
+ "vxor.vv v24, v24, v24\n"
+ "vadd.vi v0, v0, 15\n"
+ "vadd.vi v8, v8, 15\n"
+ "vadd.vi v16, v16, 15\n"
+ "vadd.vi v24, v24, 15\n"
+ "csrrsi zero, vxrm, 3\n"
+ "csrrsi zero, vxsat, 1\n");
+ asm volatile ("nop"); /* vu_reset_end */
+}
+
+int
+main ()
+{
+ unsigned vlenb_value = do_vlenb_read ();
+ (void) vlenb_value;
+ reset_vu ();
+ /* vect_test_start */
+ for (int i = 0; i < 777; ++i)
+ reset_vu ();
+ return 0; /* vect_test_end */
+}
diff --git a/gdb/testsuite/gdb.arch/riscv-vu-rwr.exp b/gdb/testsuite/gdb.arch/riscv-vu-rwr.exp
new file mode 100644
index 00000000000..1b89d87540e
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vu-rwr.exp
@@ -0,0 +1,173 @@
+# Copyright 2026 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+require {istarget "riscv*-*-*"}
+
+if {![riscv_support_rvv]} {
+ unsupported "RVV unsupported"
+ return
+}
+
+standard_testfile
+load_lib riscv64-rvv-lib.exp
+
+proc test_vu_rwr_get_default_vtype_pattern {} {
+ return "0xc3\tLMUL:3 \\(8\\) SEW:0 \\(e8\\) vta:1 \\(ta\\) vma:1 \\(ma\\) vill:0"
+}
+proc test_vu_rwr_get_zero_vtype_pattern {} {
+ return "0x0\tLMUL:0 \\(1\\) SEW:0 \\(e8\\) vta:0 \\(tu\\) vma:0 \\(mu\\) vill:0"
+}
+proc test_vu_rwr_get_default_vl {VLENB} {
+ return [riscvlib_get_vlmax $VLENB 8 e8]
+}
+proc test_vu_rwr_get_zero_vtype_vl {VLENB} {
+ return [riscvlib_get_vlmax $VLENB 1 e8]
+}
+
+proc test_vu_rwr_is_reg_excluded {excluded reg} {
+ return [expr { [lsearch -exact $excluded $reg] != -1 }]
+}
+
+proc test_vu_rwr_csr_scan { VLENB test_info exclude } {
+ set the_proc [lindex [info level 0] 0]
+ if {![test_vu_rwr_is_reg_excluded $exclude "vtype"]} {
+ set vtype_pattern [test_vu_rwr_get_default_vtype_pattern]
+ gdb_test "info reg vtype" $vtype_pattern "$the_proc: info reg vtype - $test_info"
+ }
+ if {![test_vu_rwr_is_reg_excluded $exclude "vcsr"]} {
+ gdb_test "info reg vcsr" "0x7\tVXSAT:1 VXRM:3" "$the_proc: info reg vcsr - $test_info"
+ }
+ if {![test_vu_rwr_is_reg_excluded $exclude "vl"]} {
+ set vl [test_vu_rwr_get_default_vl $VLENB]
+ gdb_test "info reg vl" "[format 0x%x $vl]\t$vl" "$the_proc: info reg vl - $test_info"
+ }
+ if {![test_vu_rwr_is_reg_excluded $exclude "vstart"]} {
+ gdb_test "info reg vstart" "0x0\t0" "$the_proc: info reg vstart - $test_info"
+ }
+ if {![test_vu_rwr_is_reg_excluded $exclude "vlenb"]} {
+ gdb_test "info reg vlenb" "[format 0x%x $VLENB]\t$VLENB" "$the_proc: info reg vlenb - $test_info"
+ }
+}
+
+proc test_vu_rwr_scan_context {VLENB test_info exclude} {
+ test_vu_rwr_csr_scan $VLENB $test_info $exclude
+ set 15_pattern [riscvlib_rvv_vreg_15_pattern $VLENB]
+ set the_proc [lindex [info level 0] 0]
+
+ for {set i 0} {$i < 32} {incr i} {
+ if { $exclude eq "v$i" } {
+ continue
+ }
+ gdb_test "print \$v$i" ${15_pattern} "$the_proc: print v$i - $test_info"
+ }
+}
+
+proc test_vu_rwr {VLENB} {
+ global srcfile
+
+ set the_proc [lindex [info level 0] 0]
+ set i8_fmt [riscvlib_rvv_vreg_fmt8]
+ test_vu_rwr_scan_context $VLENB "initial-scan" ""
+
+ gdb_breakpoint "$srcfile:[gdb_get_line_number vu_reset_end]"
+ gdb_continue_to_breakpoint "vu_reset_end"
+
+ for {set i 0} {$i < 32} {incr i} {
+ gdb_continue_to_breakpoint "vu_reset_end - v$i"
+ set vreg_contents {}
+ for { set j 0} {$j < $VLENB } { incr j } {
+ gdb_test_no_output "set \$v$i.${i8_fmt}\[$j\] = $j"
+ lappend vreg_contents $j
+ }
+ test_vu_rwr_scan_context $VLENB "v$i update-scan" "v$i"
+
+ set vreg_pattern [join $vreg_contents ", "]
+ gdb_test "print \$v$i" "\\\{$i8_fmt = \\{$vreg_pattern\\},.+" "print v$i - after modification"
+ }
+
+ gdb_continue_to_breakpoint "vu_reset_end - vtype"
+
+ set zero_vtype_vl [test_vu_rwr_get_zero_vtype_vl $VLENB]
+ gdb_test_no_output "set \$vl = $zero_vtype_vl"
+ gdb_test "info reg vl" "[format 0x%x $zero_vtype_vl]\t$zero_vtype_vl" "$the_proc: info reg vl - vl after vtype update"
+
+ set zero_vtype_pattern [test_vu_rwr_get_zero_vtype_pattern]
+ gdb_test_no_output "set \$vtype = 0"
+ gdb_test "info reg vtype" $zero_vtype_pattern "$the_proc: info reg vtype - csr update"
+
+ test_vu_rwr_scan_context $VLENB "vtype update-scan" {vtype vl}
+ gdb_test "stepi" ".*" "$the_proc: stepi after vtype update"
+ gdb_test "info reg vtype" $zero_vtype_pattern "$the_proc: info reg vtype - csr update and stepi"
+ gdb_test "info reg vl" "[format 0x%x $zero_vtype_vl]\t$zero_vtype_vl" "$the_proc: info reg vl - vl after vtype update and stepi"
+
+ gdb_continue_to_breakpoint "vu_reset_end - vcsr"
+ gdb_test_no_output "set \$vcsr = 0"
+ test_vu_rwr_scan_context $VLENB "vcsr update-scan" "vcsr"
+ gdb_test "info reg vcsr" "0x0\tVXSAT:0 VXRM:0" "$the_proc: info reg vcsr - csr update"
+ gdb_test "stepi" ".*" "$the_proc: stepi after vcsr update"
+ gdb_test "info reg vcsr" "0x0\tVXSAT:0 VXRM:0" "$the_proc: info reg vcsr - after stepi"
+
+ gdb_continue_to_breakpoint "vu_reset_end - vl"
+ gdb_test_no_output "set \$vl = 2"
+ test_vu_rwr_scan_context $VLENB "vl update-scan" "vl"
+ gdb_test "info reg vl" "[format 0x%x 2]\t2" "$the_proc: info reg vl - csr update"
+ gdb_test "stepi" ".*" "$the_proc: stepi after vl update"
+ gdb_test "info reg vl" "0x2\t2" "$the_proc: info reg vl - after stepi"
+
+ gdb_continue_to_breakpoint "vu_reset_end - vstart"
+ gdb_test_no_output "set \$vstart = 2"
+ test_vu_rwr_scan_context $VLENB "vstart update-scan" "vstart"
+ gdb_test "info reg vstart" "0x2\t2" "$the_proc: info reg vstart - vsart update"
+ gdb_test "stepi" ".*" "$the_proc: stepi after vstart update"
+ gdb_test "info reg vstart" "0x2\t2" "$the_proc: info reg vstart - after stepi"
+ gdb_continue_to_breakpoint "vu_reset_end - vstart reset"
+ gdb_test "info reg vstart" "0x0\t0" "$the_proc: info reg vstart - after reset"
+
+ gdb_continue_to_breakpoint "vu_reset_end - vlenb"
+ gdb_test_no_output "set \$vlenb = 0"
+
+ test_vu_rwr_scan_context $VLENB "$the_proc: vlenb update-scan" ""
+ gdb_test "stepi" ".*" "$the_proc: stepi after vlenb update"
+ test_vu_rwr_scan_context $VLENB "$the_proc: final scan after stepi" ""
+}
+
+proc prepare_vu_rwr_test {} {
+ global testfile
+ global srcfile
+
+ set compile_flags {}
+ lappend compile_flags debug
+ lappend compile_flags "additional_flags=-march=rv64gc"
+
+ if {[prepare_for_testing "failed to prepare" $testfile $srcfile $compile_flags]} {
+ return -1
+ }
+
+ if {![runto_main]} {
+ return -1
+ }
+
+ gdb_breakpoint "$srcfile:[gdb_get_line_number vect_test_start]"
+ gdb_continue_to_breakpoint "vect_test_start"
+
+ return 0
+}
+
+if {[prepare_vu_rwr_test]} {
+ untested "could not initialize"
+ return -1
+}
+set vlenb [riscvlib_rvv_get_csr vlenb "$testfile"]
+test_vu_rwr $vlenb
diff --git a/gdb/testsuite/gdb.arch/riscv-vu-side-effects.c b/gdb/testsuite/gdb.arch/riscv-vu-side-effects.c
new file mode 100644
index 00000000000..136ea1b15ff
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vu-side-effects.c
@@ -0,0 +1,86 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2026 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+asm (".option arch, +v\n");
+
+#include <stdlib.h>
+#include <limits.h>
+
+unsigned
+do_vlenb_read ()
+{
+ unsigned vlenb;
+ asm volatile ("csrr %[vlenb], vlenb" : [vlenb] "=r"(vlenb) : :);
+ return vlenb;
+}
+
+char *STORAGE;
+
+void
+zero_out_vu ()
+{
+ unsigned vl;
+ asm volatile ("vsetvli %[new_vl], x0, e8, m8, tu, mu"
+ : [new_vl] "=r"(vl)
+ :
+ :);
+ asm volatile ("vxor.vv v0, v0, v0");
+ asm volatile ("vxor.vv v8, v8, v8");
+ asm volatile ("vxor.vv v16, v16, v16");
+ asm volatile ("vxor.vv v24, v24, v24");
+}
+
+void
+do_wide_operations ()
+{
+ unsigned vl;
+ asm volatile ("vsetvli %[new_vl], x0, e8, m8, tu, mu"
+ : [new_vl] "=r"(vl)
+ :
+ :);
+ asm volatile ("vadd.vi v0, v0, 0x1"); /* vect_wide_op_start */
+ asm volatile ("vadd.vi v24, v0, 0x2"); /* vect_op_v0_add1 */
+ asm volatile ("vadd.vi v16, v8, 0x2"); /* vect_op_v24_v0_add2 */
+ asm volatile ("vadd.vi v10, v9, 0x3"); /* vect_op_v16_v8_add2 */
+ asm volatile ("nop"); /* vect_wide_op_end */
+}
+
+void
+do_controlled_vadd ()
+{
+ unsigned vl;
+ asm volatile ("vsetvli %[new_vl], x0, e8, m1, tu, mu"
+ : [new_vl] "=r"(vl)
+ :
+ :);
+ asm volatile ("vadd.vv v2, v1, v0"); /* vect_control_vadd_start */
+ asm volatile ("nop"); /* controlled_vadd_done */
+}
+
+int
+main ()
+{
+ unsigned vlenb_value = do_vlenb_read ();
+ STORAGE = (char *) calloc (1, vlenb_value * CHAR_BIT);
+
+ zero_out_vu ();
+ /* vect_test_start */
+ do_controlled_vadd ();
+ zero_out_vu ();
+ do_wide_operations ();
+ return 0; /* vect_test_end */
+}
diff --git a/gdb/testsuite/gdb.arch/riscv-vu-side-effects.exp b/gdb/testsuite/gdb.arch/riscv-vu-side-effects.exp
new file mode 100644
index 00000000000..1239c365469
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-vu-side-effects.exp
@@ -0,0 +1,162 @@
+# Copyright 2026 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+require {istarget "riscv*-*-*"}
+
+if {![riscv_support_rvv]} {
+ unsupported "RVV unsupported"
+ return
+}
+
+standard_testfile
+load_lib riscv64-rvv-lib.exp
+
+proc test_vu_controlled_add {VLENB} {
+ global srcfile
+
+ set i8_fmt [riscvlib_rvv_vreg_fmt8]
+ set zero_pattern [riscvlib_rvv_vreg_zero_pattern $VLENB]
+
+ gdb_breakpoint "$srcfile:[gdb_get_line_number vect_control_vadd_start]"
+ gdb_continue_to_breakpoint "vect_control_vadd_start"
+
+ set the_proc [lindex [info level 0] 0]
+
+ # ensure that state is pristine
+ for { set vregn 0 } { $vregn < 32 } { incr vregn } {
+ gdb_test "print \$v${vregn}" ${zero_pattern} "$the_proc: print v${vregn} - pristine"
+ }
+
+ # update v0
+ for {set i 0} {$i < $VLENB} {incr i} {
+ set val [expr {$i % 256 - 128}]
+ gdb_test_no_output "set \$v0.${i8_fmt}\[$i\] = $val"
+ lappend v0_contents $val
+ }
+
+ # update v1
+ for {set i 0} {$i < $VLENB} {incr i} {
+ set val [expr {($i + 7) % 256 - 128}]
+ gdb_test_no_output "set \$v1.${i8_fmt}\[$i\] = $val"
+ lappend v1_contents $val
+ }
+
+ gdb_breakpoint "$srcfile:[gdb_get_line_number controlled_vadd_done]"
+ # execute addition operation, v3 register must be updated to summ of v0 and v1
+ gdb_continue_to_breakpoint "controlled_vadd_done"
+
+ set v0_pattern [join $v0_contents ", "]
+ gdb_test "print \$v0" "\\\{$i8_fmt = \\{$v0_pattern\\},.+" "$the_proc: print v0 - after add"
+
+ set v1_pattern [join $v1_contents ", "]
+ gdb_test "print \$v1" "\\\{$i8_fmt = \\{$v1_pattern\\},.+" "$the_proc: print v1 - after add"
+ for {set i 0} {$i < $VLENB} {incr i} {
+ lappend v2_contents [expr {($i + $i + 7 + 128) % 256 - 128}]
+ }
+ set v2_pattern [join $v2_contents ", "]
+ gdb_test "print \$v2" "\\\{$i8_fmt = \\{$v2_pattern\\},.+" "$the_proc: print v2 - add result"
+ for { set vregn 3 } { $vregn < 32 } { incr vregn } {
+ gdb_test "print \$v${vregn}" ${zero_pattern} "$the_proc: print v${vregn} - pristine after add"
+ }
+}
+
+proc test_vu_wide_operations {VLENB} {
+ global srcfile
+
+ set i8_fmt [riscvlib_rvv_vreg_fmt8]
+ set the_proc [lindex [info level 0] 0]
+
+ gdb_breakpoint "$srcfile:[gdb_get_line_number vect_wide_op_start]"
+ gdb_continue_to_breakpoint "vect_wide_op_start"
+
+ gdb_breakpoint "$srcfile:[gdb_get_line_number vect_op_v0_add1]"
+ gdb_continue_to_breakpoint "vect_op_v0_add1"
+
+ gdb_test_no_output "set \$vl = 2"
+ gdb_breakpoint "$srcfile:[gdb_get_line_number vect_op_v24_v0_add2]"
+ gdb_continue_to_breakpoint "vect_op_v24_v0_add2"
+
+ for {set i 0} {$i < $VLENB} {incr i} {
+ gdb_test_no_output "set \$v8.${i8_fmt}\[$i\] = $i"
+ lappend v8_contents $i
+ }
+
+ gdb_breakpoint "$srcfile:[gdb_get_line_number vect_op_v16_v8_add2]"
+ gdb_continue_to_breakpoint "vect_op_v16_v8_add2"
+
+ gdb_test_no_output "set \$vtype = 0"
+
+ gdb_breakpoint "$srcfile:[gdb_get_line_number vect_wide_op_end]"
+ gdb_continue_to_breakpoint "vect_wide_op_end"
+
+ set vtype_pattern "0x0\tLMUL:0 \\(1\\) SEW:0 \\(e8\\) vta:0 \\(tu\\) vma:0 \\(mu\\) vill:0"
+ gdb_test "info reg vtype" "${vtype_pattern}" "$the_proc: info reg vtype - end state"
+ gdb_test "info reg vcsr" "0x0\tVXSAT:0 VXRM:0" "$the_proc: info reg vcsr - end state"
+ gdb_test "info reg vl" "[format 0x%x 2]\t2" "$the_proc: info reg vl - end state"
+ gdb_test "info reg vstart" "0x0\t0" "$the_proc: info reg vstart - end state"
+ gdb_test "info reg vlenb" "[format 0x%x $VLENB]\t$VLENB" "$the_proc: info reg vlenb - end state"
+
+ set zero_pattern [riscvlib_rvv_vreg_zero_pattern $VLENB]
+ set ones_pattern [riscvlib_rvv_vreg_1_pattern $VLENB]
+ foreach vregn { 0 1 2 3 4 5 6 7 } {
+ gdb_test "print \$v${vregn}" ${ones_pattern} "$the_proc: print v${vregn} - end state"
+ }
+ foreach vregn { 9 11 12 13 14 15 17 18 19 20 21 22 23 25 26 27 28 29 30 31} {
+ gdb_test "print \$v${vregn}" ${zero_pattern} "$the_proc: print v${vregn} - end state"
+ }
+ set xn_zeroes_rep [riscvlib_rvv_vreg_component_pattern [expr {$VLENB - 2}] 0]
+ # for VLENB = 16 we have:
+ # v10 \{i8 = {3, 3, 0 <repeats 14 times>} ...
+ # v16 \{i8 = {2, 3, 0 <repeats 14 times>} ...
+ # v24 \{i8 = {3, 3, 0 <repeats 14 times>} ...
+ foreach vregn { 10 24 } {
+ gdb_test "print \$v${vregn}" "\\\{$i8_fmt = \\{3, 3, ${xn_zeroes_rep}\\},.+" "$the_proc: print v${vregn} - end state"
+ }
+ gdb_test "print \$v16" "\\\{$i8_fmt = \\{2, 3, ${xn_zeroes_rep}\\},.+" "$the_proc: print v16 - end state"
+
+ # v8 \{i8 = {0, 1, 2, ...} ....
+ set v8_pattern [join $v8_contents ", "]
+ gdb_test "print \$v8" "\\\{$i8_fmt = \\{$v8_pattern\\},.+" "$the_proc: print v8 - end state"
+}
+
+proc prepare_vu_rw_test {} {
+ global testfile
+ global srcfile
+
+ set compile_flags {}
+ lappend compile_flags debug
+ lappend compile_flags "additional_flags=-march=rv64gc"
+
+ if {[prepare_for_testing "failed to prepare" $testfile $srcfile $compile_flags]} {
+ return -1
+ }
+
+ if {![runto_main]} {
+ return -1
+ }
+
+ gdb_breakpoint "$srcfile:[gdb_get_line_number vect_test_start]"
+ gdb_continue_to_breakpoint "vect_test_start"
+
+ return 0
+}
+
+if {[prepare_vu_rw_test]} {
+ untested "could not initialize"
+ return -1
+}
+set vlenb [riscvlib_rvv_get_csr vlenb "$testfile"]
+test_vu_controlled_add $vlenb
+test_vu_wide_operations $vlenb
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 1ebdaf6ba10..a0b50dd84b0 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -5754,6 +5754,130 @@ proc skip_inline_var_tests {} {
return 0
}
+# Run a test on the target to see if supports RISC-V Vector Extension.
+# Return 1 if so, 0 if it does not. Note this causes a restart of GDB.
+
+gdb_caching_proc riscv_support_rvv {} {
+ global srcdir gdb_prompt inferior_exited_re
+
+ set compile_flags {"debug"}
+ lappend compile_flags "additional_flags=-march=rv64gcv"
+
+ set src {
+ int main ()
+ {
+ __asm__ __volatile__ ("vsetvli t0, x0, e8, m1, ta, ma"
+ : : : "t0");
+ return 0;
+ }
+ }
+
+ set bin_name "riscv_support_rvv"
+
+ if {![gdb_simple_compile $bin_name $src executable $compile_flags]} {
+ return 0
+ }
+
+ clean_restart
+ gdb_load $obj
+
+ gdb_run_cmd
+
+ gdb_expect {
+ -re ".*Illegal instruction.*${gdb_prompt} $" {
+ set rvv_support 0
+ }
+ -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
+ set rvv_support 1
+ }
+ default {
+ warning "default case taken"
+ set rvv_support 0
+ }
+ }
+
+ gdb_exit
+
+ remote_file build delete $obj
+
+ return $rvv_support
+}
+
+# Test if choosen compiler supports RISC-V Vector Intrinsic
+
+gdb_caching_proc riscv_support_rvv_intrinsic {} {
+ global srcdir gdb_prompt inferior_exited_re
+
+ set compile_flags {"debug"}
+ lappend compile_flags "additional_flags=-march=rv64gcv"
+
+ set src {
+ #include <riscv_vector.h>
+
+ int main ()
+ {
+ const unsigned int n = 64;
+ vint64m1_t a = __riscv_vmv_v_x_i64m1 (42, n);
+ return 0;
+ }
+ }
+
+ set bin_name "riscv_support_rvv_intrinsic"
+
+ if {![gdb_simple_compile $bin_name $src executable $compile_flags]} {
+ return 0
+ }
+
+ return 1
+}
+
+# Return 1 if the compiler and target support the RISC-V Zvfh extension.
+
+gdb_caching_proc riscv_support_zvfh {} {
+ global gdb_prompt inferior_exited_re
+
+ set compile_flags {"debug"}
+ lappend compile_flags "additional_flags=-march=rv64gc_zve32f_zvfh"
+
+ set src {
+ int main ()
+ {
+ __asm__ __volatile__ ("vsetivli zero, 1, e16, m1, ta, ma\n\t"
+ "vfadd.vv v0, v0, v0"
+ : : : "v0");
+ return 0;
+ }
+ }
+
+ set bin_name "riscv_support_zvfh"
+
+ if {![gdb_simple_compile $bin_name $src executable $compile_flags]} {
+ return 0
+ }
+
+ clean_restart
+ gdb_load $obj
+ gdb_run_cmd
+
+ gdb_expect {
+ -re ".*Illegal instruction.*${gdb_prompt} $" {
+ set zvfh_support 0
+ }
+ -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
+ set zvfh_support 1
+ }
+ default {
+ warning "default case taken"
+ set zvfh_support 0
+ }
+ }
+
+ gdb_exit
+ remote_file build delete $obj
+
+ return $zvfh_support
+}
+
# Return whether we allow running fork-related testcases. Targets
# that don't even have any concept of fork will just fail to compile
# the testcases and skip the tests that way if this returns true for
diff --git a/gdb/testsuite/lib/riscv64-rvv-lib.exp b/gdb/testsuite/lib/riscv64-rvv-lib.exp
new file mode 100644
index 00000000000..1804c9cdfcb
--- /dev/null
+++ b/gdb/testsuite/lib/riscv64-rvv-lib.exp
@@ -0,0 +1,347 @@
+# Copyright 2026 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+proc _riscvlib_rvv_vtype_set_lmul {vtype lmul} {
+ set mask [expr {((1 << 32) - 1) ^ 7}]
+ return [expr {($vtype & $mask) | $lmul}]
+}
+
+proc _riscvlib_rvv_vtype_set_sew {vtype sew} {
+ set mask [expr {((1 << 32) - 1) ^ (7 << 3)}]
+ return [expr {($vtype & $mask) | ($sew << 3)}]
+}
+
+proc _riscvlib_rvv_vtype_set_tail_mode {vtype tail_mode} {
+ set mask [expr {((1 << 32) - 1) ^ (1 << 6)}]
+ return [expr {($vtype & $mask) | ($tail_mode << 6)}]
+}
+
+proc _riscvlib_rvv_vtype_set_mask_mode {vtype mask_mode} {
+ set mask [expr {((1 << 32) - 1) ^ (1 << 7)}]
+ return [expr {($vtype & $mask) | ($mask_mode << 7)}]
+}
+
+proc _riscvlib_rvv_vlmul_decoder {vlmul} {
+ switch $vlmul {
+ "1/8" {
+ return 5
+ }
+ "1/4" {
+ return 6
+ }
+ "1/2" {
+ return 7
+ }
+ "1" {
+ return 0
+ }
+ "2" {
+ return 1
+ }
+ "4" {
+ return 2
+ }
+ "8" {
+ return 3
+ }
+ default {
+ return -1
+ }
+ }
+ return -1
+}
+
+proc _riscvlib_rvv_vsew_decoder {vsew} {
+ switch $vsew {
+ "e8" {
+ return 0
+ }
+ "e16" {
+ return 1
+ }
+ "e32" {
+ return 2
+ }
+ "e64" {
+ return 3
+ }
+ default {
+ return -1
+ }
+ }
+ return -1
+}
+
+proc _riscvlib_rvv_tail_decoder {vtail} {
+ switch $vtail {
+ "tu" {
+ return 0
+ }
+ "ta" {
+ return 1
+ }
+ default {
+ return -1
+ }
+ }
+ return -1
+}
+
+proc _riscvlib_rvv_mask_decoder {vmask} {
+ switch $vmask {
+ "mu" {
+ return 0
+ }
+ "ma" {
+ return 1
+ }
+ default {
+ return -1
+ }
+ }
+ return -1
+}
+
+# Available parameters:
+# vlmul: 1/8, 1/4, 1/2, 1, 2, 4, 8
+# vsew: e8, e16, e32, e64
+# In case of inconsistent parameters, 0 is returned
+proc riscvlib_is_vlmul_vsew_legal {VLENB vlmul vsew} {
+ set lmul [_riscvlib_rvv_vlmul_decoder $vlmul]
+ if {$lmul == -1} {
+ return 0
+ }
+
+ set sew_encoding [_riscvlib_rvv_vsew_decoder $vsew]
+ if {$sew_encoding == -1} {
+ return 0
+ }
+ set sew [expr {1 << ($sew_encoding + 3)}]
+
+ if {$lmul > 4} {
+ set lmul_modifier [expr {1 << (8 - $lmul)}]
+ set required_vlen [expr {$sew * $lmul_modifier}]
+ set vlen [expr {$VLENB * 8}]
+ return [expr {$vlen >= $required_vlen}]
+ }
+ if {$lmul < 4} {
+ set lmul_modifier [expr {1 << $lmul}]
+ set required_vlen $sew
+ set vlen [expr {$VLENB * 8 * $lmul_modifier}]
+ return [expr {$vlen >= $required_vlen}]
+ }
+
+ return 0
+}
+
+# Available parameters:
+# vlmul: 1/8, 1/4, 1/2, 1, 2, 4, 8
+# vsew: e8, e16, e32, e64
+# In case of inconsistent parameters, 0 is returned
+proc riscvlib_get_vlmax {VLENB vlmul vsew} {
+ if {![riscvlib_is_vlmul_vsew_legal $VLENB $vlmul $vsew]} {
+ return 0
+ }
+ set lmul [_riscvlib_rvv_vlmul_decoder $vlmul]
+ set sew [expr {1 << ([_riscvlib_rvv_vsew_decoder $vsew] + 3)}]
+ set vlen [expr {$VLENB * 8}]
+ set vlmax 0
+
+ if {$lmul > 4} {
+ set lmul_modifier [expr {1 << (8 - $lmul)}]
+ return [expr {$vlen / ($lmul_modifier * $sew)}]
+ }
+
+ if {$lmul < 4} {
+ set lmul_modifier [expr {1 << $lmul}]
+ return [expr {$vlen * $lmul_modifier / $sew}]
+ }
+
+ return 0
+}
+
+# Available parameters:
+# vlmul: 1/8, 1/4, 1/2, 1, 2, 4, 8
+# vsew: e8, e16, e32, e64
+# In case of inconsistent parameters, 0 is returned
+proc riscvlib_get_allowed_vl {VLENB vlmul vsew vl} {
+ set vlmax [riscvlib_get_vlmax $VLENB $vlmul $vsew]
+
+ if {$vl > $vlmax} {
+ return $vlmax
+ }
+
+ return $vl
+}
+
+proc riscvlib_rvv_get_csr {name test_id} {
+ global hex
+ global decimal
+ global gdb_prompt
+ global gdb_test_name
+
+ gdb_test_multiple "info registers $name" "" {
+ -re "^info registers\[^\r\n\]+\r\n" {
+ exp_continue
+ }
+ -re "^$name\\s+(${hex})\\s+\[^\n]+\r\n" {
+ set value [expr {$expect_out(1,string)}]
+ exp_continue
+ }
+ -re "^$gdb_prompt $" {
+ pass "$gdb_test_name $test_id"
+ }
+ }
+ return $value
+}
+
+# Return a pattern matching an RVV tuple printed either as an array of
+# vectors or as a structure with an __val array. FIELD_PATTERNS contains
+# one regular expression per vector, including its enclosing braces.
+proc riscvlib_rvv_tuple_pattern {field_patterns} {
+ set fields [join $field_patterns ", "]
+ return "\\{(?:__val = \\{${fields}\\}|${fields})\\}"
+}
+
+proc riscvlib_rvv_vreg_fmt8 {} {
+ return i8
+}
+proc riscvlib_rvv_vreg_fmt16 {} {
+ return i16
+}
+proc riscvlib_rvv_vreg_fmt32 {} {
+ return i32
+}
+proc riscvlib_rvv_vreg_fmt64 {} {
+ return i64
+}
+
+proc riscvlib_rvv_vreg_print_pattern { i8 i16 i32 i64 half f32 f64} {
+ set I8_FMT [riscvlib_rvv_vreg_fmt8]
+ set I16_FMT [riscvlib_rvv_vreg_fmt16]
+ set I32_FMT [riscvlib_rvv_vreg_fmt32]
+ set I64_FMT [riscvlib_rvv_vreg_fmt64]
+ set HALF_FMT half
+ set F32_FMT f32
+ set F64_FMT f64
+ return [join [list \
+ "\\\{${I8_FMT} = \\{$i8\\}" \
+ "${I16_FMT} = \\{$i16\\}" \
+ "${I32_FMT} = \\{$i32\\}" \
+ "${I64_FMT} = \\{$i64\\}" \
+ "${HALF_FMT} = \\{$half\\}" \
+ "${F32_FMT} = \\{$f32\\}" \
+ "${F64_FMT} = \\{$f64\\}\\\}" \
+ ] ", "]
+}
+
+proc riscvlib_rvv_vreg_component_pattern {repeat_count symbol {collapse_allowed 1}} {
+ if { $collapse_allowed } {
+ if { $repeat_count > 8 } {
+ return "$symbol <repeats $repeat_count times>"
+ }
+ }
+ return [join [lrepeat $repeat_count $symbol] ", "]
+}
+
+proc riscvlib_rvv_vreg_zero_pattern {vlenb} {
+ set zero_symbol 0
+ set pattern [list \
+ [riscvlib_rvv_vreg_component_pattern $vlenb $zero_symbol] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 2 }] $zero_symbol] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 4 }] $zero_symbol] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 8 }] $zero_symbol] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 2 }] $zero_symbol] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 4 }] $zero_symbol] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 8 }] $zero_symbol] \
+ ]
+ return [riscvlib_rvv_vreg_print_pattern {*}$pattern]
+}
+
+proc riscvlib_rvv_vreg_1_pattern {vlenb} {
+ set pattern [list \
+ [riscvlib_rvv_vreg_component_pattern $vlenb 1] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 2 }] 257] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 4 }] 16843009] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 8 }] 72340172838076673] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 2 }] 1.5318e-05] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 4 }] 2.36942783e-38] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 8 }] 7.7486041854893479e-304] \
+ ]
+ return [riscvlib_rvv_vreg_print_pattern {*}$pattern]
+}
+
+proc riscvlib_rvv_vreg_3_pattern {vlenb} {
+ set zero_symbol 0
+ set pattern [list \
+ [riscvlib_rvv_vreg_component_pattern $vlenb 3] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 2 }] 771] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 4 }] 50529027] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 8 }] 217020518514230019] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 2 }] 4.5955e-05] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 4 }] 3.85008973e-37] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 8 }] 3.7209743448696002e-294] \
+ ]
+ return [riscvlib_rvv_vreg_print_pattern {*}$pattern]
+}
+
+proc riscvlib_rvv_vreg_15_pattern {vlenb} {
+ set zero_symbol 0
+ set pattern [list \
+ [riscvlib_rvv_vreg_component_pattern $vlenb 15] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 2 }] 3855] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 4 }] 252645135] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 8 }] 1085102592571150095] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 2 }] 0.00043082] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 4 }] 7.05334452e-30] \
+ [riscvlib_rvv_vreg_component_pattern [expr { $vlenb / 8 }] 3.8157368271180168e-236] \
+ ]
+ return [riscvlib_rvv_vreg_print_pattern {*}$pattern]
+}
+
+# Available parameters:
+# vlmul: 1/8, 1/4, 1/2, 1, 2, 4, 8
+# vsew: e8, e16, e32, e64
+# vtail: ta, tu
+# vmask: ma, mu
+# In case of inconsistent parameters, -1 is returned
+proc riscvlib_rvv_get_vtype_val {vlmul vsew vtail vmask} {
+ set res 0
+ set lmul [_riscvlib_rvv_vlmul_decoder $vlmul]
+ if {$lmul == -1} {
+ return -1
+ }
+ set res [_riscvlib_rvv_vtype_set_lmul $res $lmul]
+
+ set sew [_riscvlib_rvv_vsew_decoder $vsew]
+ if {$sew == -1} {
+ return -1
+ }
+ set res [_riscvlib_rvv_vtype_set_sew $res $sew]
+
+ set tail [_riscvlib_rvv_tail_decoder $vtail]
+ if {$tail == -1} {
+ return -1
+ }
+ set res [_riscvlib_rvv_vtype_set_tail_mode $res $tail]
+
+ set mask [_riscvlib_rvv_mask_decoder $vmask]
+ if {$mask == -1} {
+ return -1
+ }
+ set res [_riscvlib_rvv_vtype_set_mask_mode $res $mask]
+
+ return $res
+}
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-25 17:31 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-25 17:29 [PATCH v2 0/3] RISC-V Vector Extension support Kirill Radkin
2026-09-25 17:29 ` [PATCH v2 1/3] RISC-V Vector Extension Support Kirill Radkin
2026-09-25 17:29 ` [PATCH v2 2/3] Reverse execution support for RISC-V Vector Extension Kirill Radkin
2026-09-25 17:29 ` [PATCH v2 3/3] RISC-V Vector Extension Support Testing Kirill Radkin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox