[llvm-branch-commits] [lldb] [lldb][RISCV][test] Add RVV API tests (PR #184309)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Mar 3 01:55:42 PST 2026


https://github.com/daniilavdeev created https://github.com/llvm/llvm-project/pull/184309

Support RISC-V vector register context (3/3)

Add API tests for RISC-V vector extension support, covering:
- Register availability detection
- VCSR register consistency checks
- Register access

>From e68867a8b04de97c26873c41a7ff464d7cde2163 Mon Sep 17 00:00:00 2001
From: Daniil Avdeev <daniilavdeev237 at gmail.com>
Date: Sat, 1 Nov 2025 17:30:12 +0000
Subject: [PATCH] [lldb][RISCV][test] Add RVV API tests

Support RISC-V vector register context (3/3)

Add API tests for RISC-V vector extension support, covering:
- Register availability detection
- VCSR register consistency checks
- Register access
---
 .../Python/lldbsuite/test/lldbtest.py         |   5 +
 .../packages/Python/lldbsuite/test/rvvutil.py |  69 +++++++++++
 lldb/test/API/riscv/rvv-availability/Makefile |   3 +
 .../rvv-availability/TestRVVAvailability.py   |  47 +++++++
 lldb/test/API/riscv/rvv-availability/main.cpp |  21 ++++
 lldb/test/API/riscv/rvv-consistency/Makefile  |   3 +
 .../rvv-consistency/TestRVVConsistency.py     | 115 ++++++++++++++++++
 lldb/test/API/riscv/rvv-consistency/main.cpp  |  33 +++++
 lldb/test/API/riscv/rvv-printout/Makefile     |   3 +
 .../API/riscv/rvv-printout/TestRVVPrintout.py |  54 ++++++++
 lldb/test/API/riscv/rvv-printout/main.cpp     |  42 +++++++
 lldb/test/API/riscv/rvv-rwr/Makefile          |   3 +
 .../API/riscv/rvv-rwr/TestRVVReadWrite.py     |  53 ++++++++
 lldb/test/API/riscv/rvv-rwr/main.cpp          |  31 +++++
 lldb/test/API/riscv/rvv-side-effects/Makefile |   3 +
 .../rvv-side-effects/TestRVVSideEffects.py    |  88 ++++++++++++++
 lldb/test/API/riscv/rvv-side-effects/main.cpp |  43 +++++++
 lldb/test/API/riscv/rvv-unsupported/Makefile  |   3 +
 .../rvv-unsupported/TestRVVUnsupported.py     |  32 +++++
 lldb/test/API/riscv/rvv-unsupported/main.cpp  |   4 +
 .../API/riscv/rvv-vcsr-consistency/Makefile   |   3 +
 .../TestRVVConsistencyVCSR.py                 |  84 +++++++++++++
 .../API/riscv/rvv-vcsr-consistency/main.cpp   |  79 ++++++++++++
 23 files changed, 821 insertions(+)
 create mode 100644 lldb/packages/Python/lldbsuite/test/rvvutil.py
 create mode 100644 lldb/test/API/riscv/rvv-availability/Makefile
 create mode 100644 lldb/test/API/riscv/rvv-availability/TestRVVAvailability.py
 create mode 100644 lldb/test/API/riscv/rvv-availability/main.cpp
 create mode 100644 lldb/test/API/riscv/rvv-consistency/Makefile
 create mode 100644 lldb/test/API/riscv/rvv-consistency/TestRVVConsistency.py
 create mode 100644 lldb/test/API/riscv/rvv-consistency/main.cpp
 create mode 100644 lldb/test/API/riscv/rvv-printout/Makefile
 create mode 100644 lldb/test/API/riscv/rvv-printout/TestRVVPrintout.py
 create mode 100644 lldb/test/API/riscv/rvv-printout/main.cpp
 create mode 100644 lldb/test/API/riscv/rvv-rwr/Makefile
 create mode 100644 lldb/test/API/riscv/rvv-rwr/TestRVVReadWrite.py
 create mode 100644 lldb/test/API/riscv/rvv-rwr/main.cpp
 create mode 100644 lldb/test/API/riscv/rvv-side-effects/Makefile
 create mode 100644 lldb/test/API/riscv/rvv-side-effects/TestRVVSideEffects.py
 create mode 100644 lldb/test/API/riscv/rvv-side-effects/main.cpp
 create mode 100644 lldb/test/API/riscv/rvv-unsupported/Makefile
 create mode 100644 lldb/test/API/riscv/rvv-unsupported/TestRVVUnsupported.py
 create mode 100644 lldb/test/API/riscv/rvv-unsupported/main.cpp
 create mode 100644 lldb/test/API/riscv/rvv-vcsr-consistency/Makefile
 create mode 100644 lldb/test/API/riscv/rvv-vcsr-consistency/TestRVVConsistencyVCSR.py
 create mode 100644 lldb/test/API/riscv/rvv-vcsr-consistency/main.cpp

diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py
index 0ba4d4203229d..e4fa746bb6cc0 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -1438,6 +1438,11 @@ def isRISCV(self):
         """Returns true if the architecture is RISCV64 or RISCV32."""
         return self.getArchitecture() in ["riscv64", "riscv32"]
 
+    def isRISCVRVV(self):
+        riscv_std_extensions_pattern = r"rv([0-9a-z]+)(_|\b)"
+        riscv_std_extensions = re.search(riscv_std_extensions_pattern, self.getCPUInfo()).group(1)
+        return self.isRISCV() and "v" in riscv_std_extensions
+
     def getArchitecture(self):
         """Returns the architecture in effect the test suite is running with."""
         return lldbplatformutil.getArchitecture()
diff --git a/lldb/packages/Python/lldbsuite/test/rvvutil.py b/lldb/packages/Python/lldbsuite/test/rvvutil.py
new file mode 100644
index 0000000000000..624c3d3d7ef9b
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/rvvutil.py
@@ -0,0 +1,69 @@
+"""
+This LLDB module contains RISC-V RVV test utilities.
+"""
+
+import lldb
+
+
+def skip_if_rvv_unsupported(test):
+    if not test.isRISCVRVV():
+        test.skipTest("RVV registers must be supported.")
+
+
+def skip_if_rvv_supported(test):
+    if test.isRISCVRVV():
+        test.skipTest("RVV registers must be unsupported.")
+
+
+def get_register_value(test, reg_name):
+    """Get a reg_name register value."""
+    frame = test.thread().GetFrameAtIndex(0)
+    reg = frame.FindRegister(reg_name)
+    if not reg.IsValid():
+        return None
+    error = lldb.SBError()
+    return reg.GetValueAsUnsigned(error)
+
+
+def get_vlenb(test):
+    """Get vlenb register value."""
+    return get_register_value(test, "vlenb")
+
+
+def get_lmul(test):
+    vtype = get_register_value(test, "vtype")
+    lmul_code = vtype & 0x7
+    if lmul_code == 4:
+        return None
+
+    is_frac = lmul_code > 3
+    lmul = 1 / (1 << (8 - lmul_code)) if is_frac else 1 << lmul_code
+    return lmul
+
+
+def get_sew(test):
+    vtype = get_register_value(test, "vtype")
+    sew_code = (vtype >> 3) & 0x7
+    if sew_code >= 4:
+        return None
+
+    sew = 8 << sew_code
+    return sew
+
+
+def calculate_vlmax(test):
+    vlenb = get_vlenb(test)
+    vlmax = vlenb * 8 / get_sew(test) * get_lmul(test)
+    return round(vlmax)
+
+
+def set_vector_register_bytes(test, reg_name, byte_list):
+    """Set vector register to specific byte values."""
+    byte_str = "{" + " ".join([f"0x{b:02x}" for b in byte_list]) + "}"
+    test.runCmd(f"register write {reg_name} '{byte_str}'")
+
+
+def check_vector_register_bytes(test, reg_name, expected_bytes):
+    """Check that vector register contains expected bytes."""
+    byte_str = "{" + " ".join([f"0x{b:02x}" for b in expected_bytes]) + "}"
+    test.expect(f"register read {reg_name}", substrs=[f"{reg_name} = {byte_str}"])
diff --git a/lldb/test/API/riscv/rvv-availability/Makefile b/lldb/test/API/riscv/rvv-availability/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-availability/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/riscv/rvv-availability/TestRVVAvailability.py b/lldb/test/API/riscv/rvv-availability/TestRVVAvailability.py
new file mode 100644
index 0000000000000..fa5f12f22272e
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-availability/TestRVVAvailability.py
@@ -0,0 +1,47 @@
+"""
+Test RISC-V RVV register availability.
+Tests that vector registers are unavailable before any vector instruction
+is executed.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import rvvutil
+from lldbsuite.test import lldbutil
+
+
+class RISCVRVVAvailabilityTestCase(TestBase):
+    def _check_vector_registers_unavailable(self):
+        """Check that all vector registers and CSRs are unavailable."""
+        for reg_name in ["vstart", "vl", "vtype", "vcsr", "vlenb", "v0", "v1", "v15", "v31"]:
+            self.expect(f"register read {reg_name}", substrs=["error:", "unavailable"])
+
+    def _check_vector_registers_available(self):
+        """Check that all vector registers and CSRs are available."""
+        for reg_name in ["vstart", "vl", "vtype", "vcsr", "vlenb", "v0", "v1", "v15", "v31"]:
+            self.expect(f"register read {reg_name}", substrs=[f"{reg_name} = "])
+
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_available_with_vlenb_read(self):
+        """Test registers available even when only vlenb is read before main."""
+        rvvutil.skip_if_rvv_unsupported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv -DREAD_VLENB_BEFORE_MAIN"})
+        lldbutil.run_to_name_breakpoint(self, "main")
+        self._check_vector_registers_available()
+
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_unavailable_without_vector_ops(self):
+        """Test registers unavailable when no vector operations performed."""
+        rvvutil.skip_if_rvv_unsupported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv"})
+        lldbutil.run_to_name_breakpoint(self, "main")
+        self._check_vector_registers_unavailable()
+
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_available_after_vsetvli(self):
+        """Test registers available after vsetvli is executed."""
+        rvvutil.skip_if_rvv_unsupported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv -DSET_VSETVLI_BEFORE_MAIN"})
+        lldbutil.run_to_name_breakpoint(self, "main")
+        self._check_vector_registers_available()
diff --git a/lldb/test/API/riscv/rvv-availability/main.cpp b/lldb/test/API/riscv/rvv-availability/main.cpp
new file mode 100644
index 0000000000000..32be2a797c125
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-availability/main.cpp
@@ -0,0 +1,21 @@
+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 main() { return 0; }
diff --git a/lldb/test/API/riscv/rvv-consistency/Makefile b/lldb/test/API/riscv/rvv-consistency/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-consistency/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/riscv/rvv-consistency/TestRVVConsistency.py b/lldb/test/API/riscv/rvv-consistency/TestRVVConsistency.py
new file mode 100644
index 0000000000000..c495f209bff4a
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-consistency/TestRVVConsistency.py
@@ -0,0 +1,115 @@
+"""
+Test RISC-V RVV state consistency and edge cases.
+Tests overflow handling, illegal configurations, and state coherence.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import rvvutil
+from lldbsuite.test import lldbutil
+
+
+class RISCVRVVConsistencyTestCase(TestBase):
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_rvv_vl_overflow(self):
+        """Test that vl is clamped to VLMAX when set too high."""
+
+        rvvutil.skip_if_rvv_unsupported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv"})
+
+        lldbutil.run_to_source_breakpoint(self, "workload_end", lldb.SBFileSpec("main.cpp"))
+
+        # Try to set vl to a huge value (9999)
+        self.runCmd("register write vl 9999")
+        self.expect("register read vl", substrs=[f"vl = 0x{9999:0>16x}"])
+
+        # Continue and check that vl is clamped
+        self.runCmd("continue")
+
+        self.expect("register read vl", substrs=[f"vl = 0x{rvvutil.calculate_vlmax(self):0>16x}"])
+
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_rvv_vl_lmul_coherence(self):
+        """Test that changing LMUL affects vl appropriately."""
+
+        rvvutil.skip_if_rvv_unsupported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv"})
+
+        lldbutil.run_to_source_breakpoint(self, "workload_end", lldb.SBFileSpec("main.cpp"))
+
+        self.runCmd("register write vtype 3")
+        self.expect("register read vtype", substrs=[f"vtype = 0x{3:0>16x}"])
+        self.runCmd("register write vl 9999")
+        self.expect("register read vl", substrs=[f"vl = 0x{9999:0>16x}"])
+
+        self.runCmd("continue")
+
+        self.assertEqual(rvvutil.get_lmul(self), 8, "LMUL should be 8")
+
+        vlenb = rvvutil.get_vlenb(self)
+        self.expect("register read vl", substrs=[f"vl = 0x{rvvutil.calculate_vlmax(self):0>16x}"])
+
+        self.runCmd("continue")
+
+        # Restore LMUL=1
+        self.runCmd("register write vtype 0")
+        self.expect("register read vtype", substrs=[f"vtype = 0x{0:0>16x}"])
+
+        self.runCmd("continue")
+
+        self.assertEqual(rvvutil.get_lmul(self), 1, "LMUL should be 1")
+
+        # Check that vl is clamped after the LMUL was reduced
+        self.expect("register read vl", substrs=[f"vl = 0x{rvvutil.calculate_vlmax(self):0>16x}"])
+
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_rvv_vstart(self):
+        """Test vstart behavior."""
+
+        rvvutil.skip_if_rvv_unsupported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv"})
+
+        lldbutil.run_to_source_breakpoint(self, "workload_end", lldb.SBFileSpec("main.cpp"))
+
+        self.runCmd("register write vstart 8")
+        self.expect("register read vstart", substrs=[f"vstart = 0x{8:0>16x}"])
+
+        self.runCmd("continue")
+
+        # vstart should be cleared to 0 by vector instructions
+        self.expect("register read vstart", substrs=[f"vstart = 0x{0:0>16x}"])
+
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_rvv_illegal_vtype(self):
+        """Test illegal vtype configuration handling."""
+        rvvutil.skip_if_rvv_unsupported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv"})
+
+        lldbutil.run_to_source_breakpoint(self, "workload_end", lldb.SBFileSpec("main.cpp"))
+
+        vlenb = rvvutil.get_vlenb(self)
+        if vlenb >= 64:
+            self.skipTest("Test requires VLENB < 64")
+
+        self.runCmd("continue")
+
+        # Set illegal vtype: SEW=64 (vsew=3), LMUL=1/8 (vlmul=5)
+        # vtype = 5 | (3 << 3) = 5 | 24 = 29
+        illegal_vtype = 5 | (3 << 3)
+        self.runCmd(f"register write vtype {illegal_vtype}")
+        self.assertEqual(rvvutil.get_sew(self), 64, "SEW should be 64")
+        self.assertAlmostEqual(rvvutil.get_lmul(self), 1 / 8, places=7, msg="LMUL should be 1/8")
+
+        self.runCmd("stepi")
+
+        vtype = rvvutil.get_register_value(self, "vtype")
+        self.assertEqual((vtype >> 63) & 1, 1, "vtype should have vill=1")
+
+        # Legalize vtype
+        self.runCmd("register write vtype 0")
+        self.expect("register read vtype", substrs=[f"vtype = 0x{0:0>16x}"])
+
+        self.runCmd("continue")
+
+        self.expect("register read vtype", substrs=[f"vtype = 0x{0:0>16x}"])
diff --git a/lldb/test/API/riscv/rvv-consistency/main.cpp b/lldb/test/API/riscv/rvv-consistency/main.cpp
new file mode 100644
index 0000000000000..82ba214deff8b
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-consistency/main.cpp
@@ -0,0 +1,33 @@
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+unsigned do_vsetvli() {
+  unsigned vl;
+  asm volatile("vsetvli %[new_vl], x0, e8, m1, ta, ma" : [new_vl] "=r"(vl) : :);
+  return vl;
+}
+
+void do_workload() {
+  unsigned long long app_vtype;
+  unsigned app_vl;
+  unsigned app_vlenb;
+  asm volatile(
+      "csrr %[vtype], vtype\n\t"
+      "csrr %[vl], vl\n\t"
+      "csrr %[vlenb], vlenb\n\t"
+
+      "vxor.vv v24, v16, v8\n\t"
+      : [vtype] "=r"(app_vtype), [vl] "=r"(app_vl), [vlenb] "=r"(app_vlenb)
+      :
+      : "memory");
+
+  asm volatile("nop\n\t"); /* workload_end */
+}
+
+int main() {
+  do_vsetvli();
+  for (int i = 0; i < 777; ++i)
+    do_workload();
+  return 0;
+}
diff --git a/lldb/test/API/riscv/rvv-printout/Makefile b/lldb/test/API/riscv/rvv-printout/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-printout/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/riscv/rvv-printout/TestRVVPrintout.py b/lldb/test/API/riscv/rvv-printout/TestRVVPrintout.py
new file mode 100644
index 0000000000000..f539ea48e44ad
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-printout/TestRVVPrintout.py
@@ -0,0 +1,54 @@
+"""
+Test RISC-V RVV register printing and formatting.
+Tests basic 'register read' commands and register listing.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import rvvutil
+from lldbsuite.test import lldbutil
+
+
+class RISCVRVVPrintoutTestCase(TestBase):
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_rvv_register_read(self):
+        """Test basic vector register printing."""
+        rvvutil.skip_if_rvv_unsupported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv"})
+
+        lldbutil.run_to_source_breakpoint(self, "pre_vect_mem", lldb.SBFileSpec("main.cpp"))
+
+        vlenb = rvvutil.get_vlenb(self)
+
+        for reg_name in ["vstart", "vtype", "vcsr"]:
+            self.expect(f"register read {reg_name}", substrs=[f"{reg_name} = 0x{0:0>16x}"])
+
+        for reg_name in ["vl", "vlenb"]:
+            self.expect(f"register read {reg_name}", substrs=[f"{reg_name} = 0x{vlenb:0>16x}"])
+
+        rvvutil.check_vector_register_bytes(self, "v0", [0 for _ in range(vlenb)])
+        rvvutil.check_vector_register_bytes(self, "v1", [1 for _ in range(vlenb)])
+        rvvutil.check_vector_register_bytes(self, "v2", [3 for _ in range(vlenb)])
+
+        for reg_num in range(3, 32):
+            rvvutil.check_vector_register_bytes(self, f"v{reg_num}", [0 for _ in range(vlenb)])
+
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_rvv_register_list(self):
+        """Test 'register read --all' includes vector registers."""
+        rvvutil.skip_if_rvv_unsupported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv"})
+
+        lldbutil.run_to_source_breakpoint(self, "pre_vect_mem", lldb.SBFileSpec("main.cpp"))
+
+        expected_regs = [f"v{i}" for i in range(32)]
+        expected_regs += ["vtype", "vcsr", "vl", "vstart", "vlenb"]
+
+        self.expect("register read --all")
+        output = self.res.GetOutput()
+
+        # Check no duplicates by counting occurrences
+        for reg in expected_regs:
+            count = output.count(f"{reg} ")
+            self.assertEqual(count, 1)
diff --git a/lldb/test/API/riscv/rvv-printout/main.cpp b/lldb/test/API/riscv/rvv-printout/main.cpp
new file mode 100644
index 0000000000000..5509935c05fb9
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-printout/main.cpp
@@ -0,0 +1,42 @@
+#include <limits.h>
+#include <stdlib.h>
+
+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\n\t"
+               "vxor.vv v8,  v8,  v8\n\t"
+               "vxor.vv v16, v16, v16\n\t"
+               "vxor.vv v24, v24, v24\n\t"
+
+               "vsetvli t0, x0, e8, m1, tu, mu\n\t"
+
+               "vadd.vi v1, v1, 0x1\n\t"
+               "vadd.vi v2, v1, 0x2\n\t"
+
+               "vs1r.v  v1, (%[mem])\n\t"
+               :
+               : [mem] "r"(STORAGE)
+               : "t0", "memory"); /* pre_vect_mem */
+  asm volatile("vl1re8.v v2, (%0)" : : "r"(STORAGE) : "memory");
+}
+
+int main() {
+  do_vector_stuff();
+  return 0;
+}
diff --git a/lldb/test/API/riscv/rvv-rwr/Makefile b/lldb/test/API/riscv/rvv-rwr/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-rwr/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/riscv/rvv-rwr/TestRVVReadWrite.py b/lldb/test/API/riscv/rvv-rwr/TestRVVReadWrite.py
new file mode 100644
index 0000000000000..275818ab1bbc2
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-rwr/TestRVVReadWrite.py
@@ -0,0 +1,53 @@
+"""
+Test RISC-V RVV register read/write operations.
+Tests writing to vector registers and CSRs and verifying persistence.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import rvvutil
+from lldbsuite.test import lldbutil
+
+
+class RISCVRVVReadWriteTestCase(TestBase):
+    def _run_check(self, reg_name, write_value, expected_value):
+        self.runCmd(f"register write {reg_name} '{write_value}'")
+        self.expect(f"register read {reg_name}", substrs=[f"{reg_name} = {expected_value}"])
+
+        self.runCmd("stepi")
+        self.expect(f"register read {reg_name}", substrs=[f"{reg_name} = {expected_value}"])
+
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_rvv_write_vector_registers(self):
+        """Test writing to vector registers v0-v31."""
+        rvvutil.skip_if_rvv_unsupported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv"})
+
+        lldbutil.run_to_source_breakpoint(self, "do_vector_stuff_end", lldb.SBFileSpec("main.cpp"))
+
+        vlenb = rvvutil.get_vlenb(self)
+        self.assertIsNotNone(vlenb, "vlenb should be readable")
+
+        for reg_num in range(32):
+            self.runCmd("continue")
+            byte_str = f"{{{' '.join([f'0x{b:02x}' for b in list(range(vlenb))])}}}"
+            self._run_check(f"v{reg_num}", byte_str, byte_str)
+
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_rvv_write_vcsrs(self):
+        """Test writing to CSRs."""
+        rvvutil.skip_if_rvv_unsupported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv"})
+
+        lldbutil.run_to_source_breakpoint(self, "do_vector_stuff_end", lldb.SBFileSpec("main.cpp"))
+
+        for reg_name in ["vstart", "vtype", "vl"]:
+            self.runCmd("continue")
+            # 1 should be a valid value for vstart, vtype, vl
+            # so we use it here
+            self._run_check(reg_name, 1, f"0x{1:0>16x}")
+
+        # vlenb is read only
+        self.runCmd("continue")
+        self.expect("register write vlenb 1", substrs=["Failed to write register"], error=True)
diff --git a/lldb/test/API/riscv/rvv-rwr/main.cpp b/lldb/test/API/riscv/rvv-rwr/main.cpp
new file mode 100644
index 0000000000000..b5c65cfc58120
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-rwr/main.cpp
@@ -0,0 +1,31 @@
+#include <limits.h>
+#include <stdlib.h>
+
+void do_vector_stuff() {
+  unsigned vl;
+  asm volatile("vsetvli %[new_vl], x0, e8, m8, ta, ma\n\t"
+
+               "vxor.vv v0,  v0,  v0\n\t"
+               "vxor.vv v8,  v8,  v8\n\t"
+               "vxor.vv v16, v16, v16\n\t"
+               "vxor.vv v24, v24, v24\n\t"
+
+               "vadd.vi v0,  v0,  15\n\t"
+               "vadd.vi v8,  v8,  15\n\t"
+               "vadd.vi v16, v16, 15\n\t"
+               "vadd.vi v24, v24, 15\n\t"
+
+               "csrrsi zero, vxrm, 3\n\t"
+               "csrrsi zero, vxsat, 1\n\t"
+               : [new_vl] "=r"(vl)
+               :
+               : "memory");
+
+  asm volatile("nop"); /* do_vector_stuff_end */
+}
+
+int main() {
+  for (int i = 0; i < 777; ++i)
+    do_vector_stuff();
+  return 0;
+}
diff --git a/lldb/test/API/riscv/rvv-side-effects/Makefile b/lldb/test/API/riscv/rvv-side-effects/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-side-effects/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/riscv/rvv-side-effects/TestRVVSideEffects.py b/lldb/test/API/riscv/rvv-side-effects/TestRVVSideEffects.py
new file mode 100644
index 0000000000000..913d40580420d
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-side-effects/TestRVVSideEffects.py
@@ -0,0 +1,88 @@
+"""
+Test RISC-V RVV register modification side effects.
+Tests that modifying vector state (vl, vtype) affects program execution correctly.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import rvvutil
+from lldbsuite.test import lldbutil
+
+
+class RISCVRVVSideEffectsTestCase(TestBase):
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_rvv_controlled_vadd(self):
+        """Test vector addition with modified register values."""
+
+        rvvutil.skip_if_rvv_unsupported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv"})
+
+        main_source_file = lldb.SBFileSpec("main.cpp")
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+            self, "vect_control_vadd_start", main_source_file
+        )
+
+        vlenb = rvvutil.get_vlenb(self)
+        self.assertIsNotNone(vlenb, "VLENB should be readable")
+
+        for i in range(32):
+            rvvutil.check_vector_register_bytes(self, f"v{i}", [0 for _ in range(vlenb)])
+
+        rvvutil.set_vector_register_bytes(self, "v0", list(range(vlenb)))
+        rvvutil.set_vector_register_bytes(self, "v1", [i + 7 for i in range(vlenb)])
+
+        # Continue to after vadd
+        lldbutil.continue_to_source_breakpoint(self, process, "controlled_vadd_done", main_source_file)
+
+        # Check that v0 and v1 are unchanged
+        rvvutil.check_vector_register_bytes(self, "v0", list(range(vlenb)))
+        rvvutil.check_vector_register_bytes(self, "v1", [i + 7 for i in range(vlenb)])
+
+        # Check that v2 contains the sum (v0 + v1)
+        rvvutil.check_vector_register_bytes(self, "v2", [i + i + 7 for i in range(vlenb)])
+
+        for i in range(3, 32):
+            rvvutil.check_vector_register_bytes(self, f"v{i}", [0 for _ in range(vlenb)])
+
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_rvv_wide_operations_with_vl_modification(self):
+        """Test that modifying vl affects subsequent operations."""
+
+        rvvutil.skip_if_rvv_unsupported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv"})
+
+        main_source_file = lldb.SBFileSpec("main.cpp")
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, "vect_op_v0_add1", main_source_file)
+
+        self.runCmd("register write vl 2")
+
+        lldbutil.continue_to_source_breakpoint(self, process, "vect_op_v24_v0_add2", main_source_file)
+
+        vlenb = rvvutil.get_vlenb(self)
+        self.assertIsNotNone(vlenb, "VLENB should be readable")
+
+        rvvutil.set_vector_register_bytes(self, "v8", list(range(vlenb)))
+
+        lldbutil.continue_to_source_breakpoint(self, process, "vect_op_v16_v8_add2", main_source_file)
+
+        self.runCmd("register write vtype 0")
+
+        lldbutil.continue_to_source_breakpoint(self, process, "vect_wide_op_end", main_source_file)
+
+        self.expect("register read vtype", substrs=[f"vtype = 0x{0:0>16x}"])
+        self.expect("register read vl", substrs=[f"vl = 0x{2:0>16x}"])
+
+        rvvutil.check_vector_register_bytes(self, "v8", list(range(vlenb)))
+
+        # Check that operations only affected first 2 elements (vl=2)
+        # v10 and v24 should have [3, 3, 0, 0, ...]
+        v10_value = [0 for _ in range(vlenb)]
+        v10_value[0:2] = [3, 3]
+        rvvutil.check_vector_register_bytes(self, "v10", v10_value)
+        rvvutil.check_vector_register_bytes(self, "v24", v10_value)
+
+        # v16 should have [2, 3, 0, 0, ...]
+        v16_value = [0 for _ in range(vlenb)]
+        v16_value[0:2] = [2, 3]
+        rvvutil.check_vector_register_bytes(self, "v16", v16_value)
diff --git a/lldb/test/API/riscv/rvv-side-effects/main.cpp b/lldb/test/API/riscv/rvv-side-effects/main.cpp
new file mode 100644
index 0000000000000..b4e6702dcc6d0
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-side-effects/main.cpp
@@ -0,0 +1,43 @@
+#include <limits.h>
+#include <stdlib.h>
+
+void zero_out_vec_ctx() {
+  unsigned vl;
+  asm volatile("vsetvli %[new_vl], x0, e8, m8, tu, mu\n\t"
+               "vxor.vv v0,  v0,  v0\n\t"
+               "vxor.vv v8,  v8,  v8\n\t"
+               "vxor.vv v16, v16, v16\n\t"
+               "vxor.vv v24, v24, v24\n\t"
+               : [new_vl] "=r"(vl)
+               :
+               : "memory");
+}
+
+void do_wide_operations() {
+  unsigned vl;
+  asm volatile("vsetvli %[new_vl], x0, e8, m8, tu, mu\n\t"
+               "vadd.vi v0,  v0,  0x1\n\t"
+               : [new_vl] "=r"(vl)
+               :
+               : "memory");
+
+  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() {
+  zero_out_vec_ctx();
+  do_controlled_vadd();
+  zero_out_vec_ctx();
+  do_wide_operations();
+  return 0;
+}
diff --git a/lldb/test/API/riscv/rvv-unsupported/Makefile b/lldb/test/API/riscv/rvv-unsupported/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-unsupported/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/riscv/rvv-unsupported/TestRVVUnsupported.py b/lldb/test/API/riscv/rvv-unsupported/TestRVVUnsupported.py
new file mode 100644
index 0000000000000..6198541f422b5
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-unsupported/TestRVVUnsupported.py
@@ -0,0 +1,32 @@
+"""
+Test RISC-V RVV behavior on targets without RVV support.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import rvvutil
+from lldbsuite.test import lldbutil
+
+
+class RISCVRVVUnsupportedTestCase(TestBase):
+    # This test should only run on RISC-V targets without RVV support
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_rvv_unsupported(self):
+        """Test that vector registers are inaccessible on non-RVV targets."""
+        rvvutil.skip_if_rvv_supported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv"})
+
+        lldbutil.run_to_source_breakpoint(self, "break", lldb.SBFileSpec("main.cpp"))
+
+        self.expect("print a", substrs=["42"])
+        self.runCmd("register write a0 42")
+        self.expect("register read a0", substrs=[f"0x{42:0>16x}"])
+
+        for reg_name in ["vstart", "vl", "vlenb", "v0", "v15", "v31"]:
+            self.expect(f"register read {reg_name}", substrs=["error:", "Invalid register name"], error=True)
+
+        # Basic debugging should still work
+        self.expect("print a", substrs=["42"])
+        self.runCmd("register write a0 43")
+        self.expect("register read a0", substrs=[f"0x{43:0>16x}"])
diff --git a/lldb/test/API/riscv/rvv-unsupported/main.cpp b/lldb/test/API/riscv/rvv-unsupported/main.cpp
new file mode 100644
index 0000000000000..646291592f927
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-unsupported/main.cpp
@@ -0,0 +1,4 @@
+int main() {
+  int a = 42;
+  return 0; /* break */
+}
diff --git a/lldb/test/API/riscv/rvv-vcsr-consistency/Makefile b/lldb/test/API/riscv/rvv-vcsr-consistency/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-vcsr-consistency/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/riscv/rvv-vcsr-consistency/TestRVVConsistencyVCSR.py b/lldb/test/API/riscv/rvv-vcsr-consistency/TestRVVConsistencyVCSR.py
new file mode 100644
index 0000000000000..05d030fea9525
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-vcsr-consistency/TestRVVConsistencyVCSR.py
@@ -0,0 +1,84 @@
+"""
+Test RISC-V RVV CSR (vtype, vcsr) consistency
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import rvvutil
+from lldbsuite.test import lldbutil
+
+
+class RISCVRVVConsistencyVCSRTestCase(TestBase):
+    def _is_lmul_sew_legal(self):
+        """Check if LMUL/SEW configuration is legal."""
+        vlenb = rvvutil.get_vlenb(self)
+        return vlenb * 8 * rvvutil.get_lmul(self) >= rvvutil.get_sew(self)
+
+    def _get_required_vl(self):
+        """Get vl value required by the application."""
+        var = self.frame().FindVariable("vl")
+        if not var.IsValid():
+            return None
+        error = lldb.SBError()
+        return var.GetValueAsUnsigned(error)
+
+    def _get_expected_vl(self):
+        """Get vl value that expected to be set."""
+        if not self._is_lmul_sew_legal():
+            return 0
+        return min(self._get_required_vl(), rvvutil.calculate_vlmax(self))
+
+    def _get_vxml(self):
+        vcsr = rvvutil.get_register_value(self, "vcsr")
+        return (vcsr >> 1) & 0b11
+
+    def _get_vxsat(self):
+        vcsr = rvvutil.get_register_value(self, "vcsr")
+        return vcsr & 0b1
+
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_rvv_vl_register(self):
+        """Test vl register for various configurations."""
+        rvvutil.skip_if_rvv_unsupported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv"})
+
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+            self, "vsetvl_done", lldb.SBFileSpec("main.cpp")
+        )
+
+        finish_bp = lldbutil.run_break_set_by_source_regexp(self, "do_vsetv_test_end")
+        finish_thread = lldbutil.get_one_thread_stopped_at_breakpoint_id(process, finish_bp)
+        while finish_thread is None:
+            if not self._is_lmul_sew_legal():
+                # For illegal configs, vtype should show vill=1
+                vtype = rvvutil.get_register_value(self, "vtype")
+                self.assertEqual((vtype >> 63) & 1, 1, "vtype should show vill=1")
+
+            self.expect("register read vl", substrs=[f"vl = 0x{self._get_expected_vl():0>16x}"])
+
+            self.runCmd("continue")
+            finish_thread = lldbutil.get_one_thread_stopped_at_breakpoint_id(process, finish_bp)
+
+    @skipIf(archs=no_match("^riscv.*"))
+    def test_rvv_vcsr_register(self):
+        """Test vcsr register."""
+
+        rvvutil.skip_if_rvv_unsupported(self)
+        self.build(dictionary={"CFLAGS_EXTRAS": "-march=rv64gcv"})
+        main_source_file = lldb.SBFileSpec("main.cpp")
+
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, "rvv_initialized", main_source_file)
+
+        # Test different vxrm values
+        for vxrm in range(4):
+            lldbutil.continue_to_source_breakpoint(self, process, f"vxrm_{vxrm}", main_source_file)
+            self.assertEqual(self._get_vxml(), vxrm, "Invalid vxrm value")
+
+        lldbutil.continue_to_source_breakpoint(self, process, "vxrm_0_again", main_source_file)
+        self.assertEqual(self._get_vxsat(), 1, "Invalid vxsat value")
+        self.assertEqual(self._get_vxml(), 3, "Invalid vxrm value")
+
+        lldbutil.continue_to_source_breakpoint(self, process, "vcsr_done", main_source_file)
+        self.assertEqual(self._get_vxsat(), 1, "Invalid vxsat value")
+        self.assertEqual(self._get_vxml(), 0, "Invalid vxrm value")
diff --git a/lldb/test/API/riscv/rvv-vcsr-consistency/main.cpp b/lldb/test/API/riscv/rvv-vcsr-consistency/main.cpp
new file mode 100644
index 0000000000000..b22437162917c
--- /dev/null
+++ b/lldb/test/API/riscv/rvv-vcsr-consistency/main.cpp
@@ -0,0 +1,79 @@
+#include <vector>
+
+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 */
+}
+
+void do_vsetv_test() {
+  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);
+}
+
+void do_vcsr_test() {
+  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]" /* vcsr_done */
+               : [new_vl] "+r"(vl), [vtype] "=r"(vtype)
+               :
+               :);
+}
+
+int main() {
+  do_vsetvli();
+  /* rvv_initialized */
+  do_vsetv_test();
+  do_vcsr_test();
+  /* do_vsetv_test_end */
+  return 0;
+}



More information about the llvm-branch-commits mailing list