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 <[email protected]> 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; +} _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
