[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