Vector configuration instructions update both the destination register
and architectural state used by subsequent vector instructions. Add
coverage for these effects before specializing vsetvli and vsetivli
translation to avoid the generic vsetvl helper.

Exercise register and immediate AVL inputs, including zero, values
around VLMAX and twice VLMAX, and large unsigned values. Check source
and destination register aliases and the x0 forms. Include LMUL=2 and
register-supplied vtype configurations to cover the generic path.

Seed VILL, vstart and vcsr before configuration, then check the
resulting vl and vtype, the clearing of vstart, and preservation of
vcsr. Check that an invalid vtype sets VILL and clears vl. Perform
vector arithmetic after selected configurations to verify that the
following instructions observe the updated state.

Register the test with rvv_vl_half_avl both disabled and enabled,
using a matching expected-VL calculation for each setting. Disable
compiler auto-vectorization when building the test.
---
 tests/tcg/riscv64/meson.build         |  13 +++
 tests/tcg/riscv64/test-vsetvl-state.c | 142 ++++++++++++++++++++++++++
 2 files changed, 155 insertions(+)
 create mode 100644 tests/tcg/riscv64/test-vsetvl-state.c

diff --git a/tests/tcg/riscv64/meson.build b/tests/tcg/riscv64/meson.build
index 0766f4e3ff..0d3a6eb4d2 100644
--- a/tests/tcg/riscv64/meson.build
+++ b/tests/tcg/riscv64/meson.build
@@ -17,6 +17,19 @@ tests += {
     'cflags': ['-nostdlib'],
     'qemu_args': ['-cpu', 'rv64,c=false'],
   },
+  'test-vsetvl-state.c': {
+    'cflags': ['-march=rv64gcv', '-fno-tree-vectorize',
+               '-fno-tree-slp-vectorize'],
+    'qemu_args': ['-cpu', 'rv64,v=true,vlen=128,elen=64,rvv_vl_half_avl=off'],
+  },
+}
+
+tests += {
+  'test-vsetvl-state.c': {
+    'test_name': 'test-vsetvl-state-half',
+    'env_var': 'RVV_TEST_HALF=1',
+    'qemu_args': ['-cpu', 'rv64,v=true,vlen=128,elen=64,rvv_vl_half_avl=on'],
+  },
 }
 
 if 'qemu-riscv64' in emulators
diff --git a/tests/tcg/riscv64/test-vsetvl-state.c 
b/tests/tcg/riscv64/test-vsetvl-state.c
new file mode 100644
index 0000000000..95ed7df1ed
--- /dev/null
+++ b/tests/tcg/riscv64/test-vsetvl-state.c
@@ -0,0 +1,142 @@
+/*
+ * Check vector configuration state, register aliases and following arithmetic.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static bool half_avl;
+
+static unsigned long expected_vl(unsigned long avl, unsigned long maximum)
+{
+    if (avl <= maximum) {
+        return avl;
+    }
+    if (half_avl && avl < 2 * maximum) {
+        return (avl + 1) / 2;
+    }
+    return maximum;
+}
+
+static void seed_state(void)
+{
+    asm volatile("vsetvl zero,zero,%0; csrwi vstart,7; csrwi vcsr,5"
+                 : : "r"(ULONG_MAX) : "memory");
+}
+
+static void check_state(unsigned long expected, unsigned long type)
+{
+    unsigned long vl, vtype, vstart, vcsr;
+
+    asm volatile("csrr %0,vl; csrr %1,vtype; csrr %2,vstart; csrr %3,vcsr"
+                 : "=r"(vl), "=r"(vtype), "=r"(vstart), "=r"(vcsr));
+    assert(vl == expected);
+    assert(vtype == type);
+    assert(vstart == 0);
+    assert(vcsr == 5);
+}
+
+static void check_arithmetic(unsigned long vl)
+{
+    unsigned long value;
+
+    if (vl == 0) {
+        return;
+    }
+    asm volatile("vmv.v.i v1,7; vadd.vi v2,v1,1; vmv.x.s %0,v2"
+                 : "=r"(value) : : "memory");
+    assert(value == 8);
+}
+
+static unsigned long configure(unsigned long avl, unsigned alias)
+{
+    unsigned long result;
+    register unsigned long same asm("a0") = avl;
+
+    switch (alias) {
+    case 0:
+        asm volatile("mv t0,%1; vsetvli t1,t0,e32,m1,tu,mu; mv %0,t1"
+                     : "=r"(result) : "r"(avl) : "t0", "t1", "memory");
+        return result;
+    case 1:
+        asm volatile("vsetvli a0,a0,e32,m1,tu,mu"
+                     : "+r"(same) : : "memory");
+        return same;
+    default:
+        asm volatile("mv t0,%1; vsetvli zero,t0,e32,m1,tu,mu; mv %0,t0"
+                     : "=r"(result) : "r"(avl) : "t0", "memory");
+        return result;
+    }
+}
+
+int main(void)
+{
+    const char *option = getenv("RVV_TEST_HALF");
+    unsigned long vlenb, maximum, result;
+
+    half_avl = option && option[0] == '1';
+    asm volatile("csrr %0,vlenb" : "=r"(vlenb));
+    maximum = vlenb / sizeof(unsigned int);
+    assert(maximum >= 4);
+
+    unsigned long requests[] = {
+        0, 1, maximum - 1, maximum, maximum + 1,
+        2 * maximum - 1, 2 * maximum, ULONG_MAX,
+        1UL << 63, 0xfedcba9876543210UL,
+    };
+
+    for (unsigned n = 0; n < sizeof(requests) / sizeof(requests[0]); n++) {
+        unsigned long wanted = expected_vl(requests[n], maximum);
+
+        for (unsigned alias = 0; alias < 3; alias++) {
+            seed_state();
+            result = configure(requests[n], alias);
+            assert(result == (alias == 2 ? requests[n] : wanted));
+            check_state(wanted, 0x10);
+            check_arithmetic(wanted);
+        }
+    }
+
+    seed_state();
+    asm volatile("vsetivli %0,5,e32,m1,tu,mu" : "=r"(result) : : "memory");
+    assert(result == expected_vl(5, maximum));
+    check_state(result, 0x10);
+    check_arithmetic(result);
+
+    seed_state();
+    asm volatile("vsetivli zero,31,e32,m1,tu,mu" : : : "memory");
+    check_state(expected_vl(31, maximum), 0x10);
+
+    seed_state();
+    asm volatile("vsetvli %0,%1,e32,m2,tu,mu"
+                 : "=r"(result) : "r"(2 * maximum + 1) : "memory");
+    assert(result == expected_vl(2 * maximum + 1, 2 * maximum));
+    check_state(result, 0x11);
+
+    seed_state();
+    asm volatile("vsetvl %0,%1,%2"
+                 : "=r"(result) : "r"(maximum + 1), "r"(0x10UL) : "memory");
+    assert(result == expected_vl(maximum + 1, maximum));
+    check_state(result, 0x10);
+
+    result = configure(2, 0);
+    assert(result == 2);
+    asm volatile("csrwi vstart,7; vsetvli zero,zero,e32,m1,tu,mu"
+                 : : : "memory");
+    check_state(2, 0x10);
+    asm volatile("vsetvli %0,zero,e32,m1,tu,mu"
+                 : "=r"(result) : : "memory");
+    assert(result == maximum);
+    check_state(maximum, 0x10);
+
+    seed_state();
+    asm volatile("vsetvl zero,%0,%1"
+                 : : "r"(1UL), "r"(ULONG_MAX) : "memory");
+    check_state(0, 1UL << 63);
+    puts("RVV configuration state: PASS");
+    return 0;
+}

base-commit: 9703b6cf418d2ce72fae8d00e511135ce0bfda43
-- 
2.47.0.windows.1


Reply via email to