From: "Philippe Mathieu-Daudé" <philmd@oss.qualcomm.com>
To: qemu-devel@nongnu.org
Cc: qemu-riscv@nongnu.org,
"Daniel Henrique Barboza" <daniel.barboza@oss.qualcomm.com>,
"Aurelien Jarno" <aurelien@aurel32.net>,
"Richard Henderson" <richard.henderson@linaro.org>,
"Alistair Francis" <Alistair.Francis@wdc.com>,
"Peter Maydell" <peter.maydell@linaro.org>,
"Palmer Dabbelt" <palmer@dabbelt.com>,
qemu-arm@nongnu.org,
"Philippe Mathieu-Daudé" <philmd@oss.qualcomm.com>
Subject: [PATCH v3 6/6] tests/tcg/aarch64: Add vector immediate regression tests
Date: Wed, 28 Oct 2026 15:33:30 +0100 [thread overview]
Message-ID: <20261028143330.6518-7-philmd@oss.qualcomm.com> (raw)
In-Reply-To: <20261028143330.6518-1-philmd@oss.qualcomm.com>
Run SVE/AdvSIMD immediate operations after an operation
of another element size, at every SVE vector length,
against scalar references.
Catches backends encoding the replicated constant or
using a stale element size, as tcg/riscv64 did.
AI-used-for: Regression tests
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
tests/tcg/aarch64/sve-vec-imm.c | 233 ++++++++++++++++++++++++++++++++
tests/tcg/aarch64/meson.build | 1 +
2 files changed, 234 insertions(+)
create mode 100644 tests/tcg/aarch64/sve-vec-imm.c
diff --git a/tests/tcg/aarch64/sve-vec-imm.c b/tests/tcg/aarch64/sve-vec-imm.c
new file mode 100644
index 000000000000..62391824946b
--- /dev/null
+++ b/tests/tcg/aarch64/sve-vec-imm.c
@@ -0,0 +1,233 @@
+/*
+ * Vector operations with immediates, at every SVE vector length.
+ *
+ * Each case first runs an operation with a given element size, then
+ * an operation with an immediate at another element size, within the
+ * same TB. This catches TCG backends that encode the immediate from
+ * the whole replicated constant, or apply it at a stale element size.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/prctl.h>
+
+#define MAXVL 256
+
+static uint8_t in[MAXVL], out[MAXVL];
+
+typedef void test_fn(void);
+typedef uint64_t ref_fn(uint64_t x);
+
+#define TEST(NAME, SETUP, OP) \
+static void NAME(void) \
+{ \
+ asm volatile("ldr z0, [%0]\n\t" \
+ "ldr z1, [%0]\n\t" \
+ "mov z2.d, #0\n\t" \
+ SETUP "\n\t" \
+ OP "\n\t" \
+ "str z0, [%1]" \
+ : : "r"(in), "r"(out) : "z0", "z1", "z2", "memory"); \
+}
+
+#define SET_B "add z1.b, z1.b, z1.b"
+#define SET_D "add z1.d, z1.d, z1.d"
+
+static int64_t sext(uint64_t x, int bits)
+{
+ return (int64_t)(x << (64 - bits)) >> (64 - bits);
+}
+
+static uint64_t sat_s(int64_t x, int bits)
+{
+ int64_t max = (1ll << (bits - 1)) - 1;
+ return x > max ? max : x < -max - 1 ? -max - 1 : x;
+}
+
+static uint64_t sat_u(int64_t x, int bits)
+{
+ int64_t max = (1ll << bits) - 1;
+ return x > max ? max : x < 0 ? 0 : x;
+}
+
+static uint64_t ror(uint64_t x, int n, int bits)
+{
+ uint64_t m = bits == 64 ? -1ull : (1ull << bits) - 1;
+ return ((x >> n) | (x << (bits - n))) & m;
+}
+
+/* Arithmetic immediates (add_vec, sub_vec, saturating ops). */
+TEST(add_b5, SET_D, "add z0.b, z0.b, #5")
+static uint64_t r_add_b5(uint64_t x) { return x + 5; }
+TEST(add_h3, SET_B, "add z0.h, z0.h, #3")
+static uint64_t r_add_h3(uint64_t x) { return x + 3; }
+TEST(sub_s7, SET_B, "sub z0.s, z0.s, #7")
+static uint64_t r_sub_s7(uint64_t x) { return x - 7; }
+TEST(subr_h3, SET_B, "subr z0.h, z0.h, #3")
+static uint64_t r_subr_h3(uint64_t x) { return 3 - x; }
+TEST(sqadd_b3, SET_D, "sqadd z0.b, z0.b, #3")
+static uint64_t r_sqadd_b3(uint64_t x) { return sat_s(sext(x, 8) + 3, 8); }
+TEST(uqadd_h9, SET_B, "uqadd z0.h, z0.h, #9")
+static uint64_t r_uqadd_h9(uint64_t x) { return sat_u(x + 9, 16); }
+TEST(sqsub_s4, SET_B, "sqsub z0.s, z0.s, #4")
+static uint64_t r_sqsub_s4(uint64_t x) { return sat_s(sext(x, 32) - 4, 32); }
+TEST(uqsub_s2, SET_B, "uqsub z0.s, z0.s, #2")
+static uint64_t r_uqsub_s2(uint64_t x) { return sat_u((int64_t)x - 2, 32); }
+
+/* Logical immediates (and_vec, or_vec, xor_vec). */
+TEST(and_d_f, SET_B, "and z0.d, z0.d, #0xf")
+static uint64_t r_and_f(uint64_t x) { return x & 0xf; }
+TEST(and_b_f, SET_D, "and z0.b, z0.b, #0xf")
+TEST(orr_d_m16, SET_B, "orr z0.d, z0.d, #0xfffffffffffffff0")
+static uint64_t r_orr_m16(uint64_t x) { return x | -16ull; }
+TEST(eor_b_f, SET_D, "eor z0.b, z0.b, #0xf")
+static uint64_t r_eor_f(uint64_t x) { return x ^ 0xf; }
+TEST(orr_h_f, SET_D, "orr z0.h, z0.h, #0xf")
+static uint64_t r_orr_f(uint64_t x) { return x | 0xf; }
+TEST(eor_s_1, SET_B, "eor z0.s, z0.s, #0x1")
+static uint64_t r_eor_1(uint64_t x) { return x ^ 1; }
+
+/* Shift immediates, including counts above 15 and 31. */
+TEST(lsl_d40, SET_B, "lsl z0.d, z0.d, #40")
+static uint64_t r_lsl_d40(uint64_t x) { return x << 40; }
+TEST(asr_d63, SET_B, "asr z0.d, z0.d, #63")
+static uint64_t r_asr_d63(uint64_t x) { return sext(x, 64) >> 63; }
+TEST(lsr_s20, SET_D, "lsr z0.s, z0.s, #20")
+static uint64_t r_lsr_s20(uint64_t x) { return x >> 20; }
+TEST(lsl_s31, SET_D, "lsl z0.s, z0.s, #31")
+static uint64_t r_lsl_s31(uint64_t x) { return x << 31; }
+TEST(asr_h15, SET_D, "asr z0.h, z0.h, #15")
+static uint64_t r_asr_h15(uint64_t x) { return sext(x, 16) >> 15; }
+TEST(xar_d40, SET_B, "xar z0.d, z0.d, z2.d, #40")
+static uint64_t r_xar_d40(uint64_t x) { return ror(x, 40, 64); }
+TEST(xar_s20, SET_D, "xar z0.s, z0.s, z2.s, #20")
+static uint64_t r_xar_s20(uint64_t x) { return ror(x, 20, 32); }
+
+/* Compare with zero (cmp_vec), including the adjusted LT/GE forms. */
+TEST(cmeq_h0, SET_B, "cmeq v0.8h, v0.8h, #0")
+static uint64_t r_cmeq0(uint64_t x) { return x == 0 ? -1ull : 0; }
+TEST(cmgt_b0, SET_D, "cmgt v0.16b, v0.16b, #0")
+static uint64_t r_cmgt_b0(uint64_t x) { return sext(x, 8) > 0 ? -1ull : 0; }
+TEST(cmlt_b0, SET_D, "cmlt v0.16b, v0.16b, #0")
+static uint64_t r_cmlt_b0(uint64_t x) { return sext(x, 8) < 0 ? -1ull : 0; }
+TEST(cmlt_h0, SET_B, "cmlt v0.8h, v0.8h, #0")
+static uint64_t r_cmlt_h0(uint64_t x) { return sext(x, 16) < 0 ? -1ull : 0; }
+TEST(cmge_s0, SET_B, "cmge v0.4s, v0.4s, #0")
+static uint64_t r_cmge_s0(uint64_t x) { return sext(x, 32) >= 0 ? -1ull : 0; }
+TEST(cmle_d0, SET_B, "cmle v0.2d, v0.2d, #0")
+static uint64_t r_cmle_d0(uint64_t x) { return sext(x, 64) <= 0 ? -1ull : 0; }
+
+/* Vector constants (dupi_vec): vmv.v.i, 0/-1, and wide immediates. */
+TEST(movi_s5, SET_B, "movi v0.4s, #5")
+static uint64_t r_5(uint64_t x) { return 5; }
+TEST(movi_h99, SET_D, "movi v0.8h, #0x99")
+static uint64_t r_99(uint64_t x) { return 0x99; }
+TEST(movi_d_mask, SET_B, "movi v0.2d, #0xff00ff00ff00ff00")
+static uint64_t r_mask(uint64_t x) { return 0xff00ff00ff00ff00ull; }
+TEST(mvni_s0, SET_D, "mvni v0.4s, #0")
+static uint64_t r_m1(uint64_t x) { return -1ull; }
+
+static const struct {
+ const char *name;
+ test_fn *fn;
+ ref_fn *ref;
+ int esz; /* element size in bytes */
+ int neon; /* AdvSIMD op: only the low 16 bytes, rest zeroed */
+} tests[] = {
+ { "add .d; add .b, #5", add_b5, r_add_b5, 1 },
+ { "add .b; add .h, #3", add_h3, r_add_h3, 2 },
+ { "add .b; sub .s, #7", sub_s7, r_sub_s7, 4 },
+ { "add .b; subr .h, #3", subr_h3, r_subr_h3, 2 },
+ { "add .d; sqadd .b, #3", sqadd_b3, r_sqadd_b3, 1 },
+ { "add .b; uqadd .h, #9", uqadd_h9, r_uqadd_h9, 2 },
+ { "add .b; sqsub .s, #4", sqsub_s4, r_sqsub_s4, 4 },
+ { "add .b; uqsub .s, #2", uqsub_s2, r_uqsub_s2, 4 },
+
+ { "add .b; and .d, #0xf", and_d_f, r_and_f, 8 },
+ { "add .d; and .b, #0xf", and_b_f, r_and_f, 1 },
+ { "add .b; orr .d, #-16", orr_d_m16, r_orr_m16, 8 },
+ { "add .d; eor .b, #0xf", eor_b_f, r_eor_f, 1 },
+ { "add .d; orr .h, #0xf", orr_h_f, r_orr_f, 2 },
+ { "add .b; eor .s, #1", eor_s_1, r_eor_1, 4 },
+
+ { "add .b; lsl .d, #40", lsl_d40, r_lsl_d40, 8 },
+ { "add .b; asr .d, #63", asr_d63, r_asr_d63, 8 },
+ { "add .d; lsr .s, #20", lsr_s20, r_lsr_s20, 4 },
+ { "add .d; lsl .s, #31", lsl_s31, r_lsl_s31, 4 },
+ { "add .d; asr .h, #15", asr_h15, r_asr_h15, 2 },
+ { "add .b; xar .d, #40", xar_d40, r_xar_d40, 8 },
+ { "add .d; xar .s, #20", xar_s20, r_xar_s20, 4 },
+
+ { "add .b; cmeq .8h, #0", cmeq_h0, r_cmeq0, 2, 1 },
+ { "add .d; cmgt .16b, #0", cmgt_b0, r_cmgt_b0, 1, 1 },
+ { "add .d; cmlt .16b, #0", cmlt_b0, r_cmlt_b0, 1, 1 },
+ { "add .b; cmlt .8h, #0", cmlt_h0, r_cmlt_h0, 2, 1 },
+ { "add .b; cmge .4s, #0", cmge_s0, r_cmge_s0, 4, 1 },
+ { "add .b; cmle .2d, #0", cmle_d0, r_cmle_d0, 8, 1 },
+
+ { "add .b; movi .4s, #5", movi_s5, r_5, 4, 1 },
+ { "add .d; movi .8h, #0x99", movi_h99, r_99, 2, 1 },
+ { "add .b; movi .2d, #0xff00...", movi_d_mask, r_mask, 8, 1 },
+ { "add .d; mvni .4s, #0", mvni_s0, r_m1, 4, 1 },
+};
+
+static int check(int vl, int t)
+{
+ int esz = tests[t].esz;
+ int n = tests[t].neon ? 16 : vl;
+ uint64_t mask = esz == 8 ? -1ull : (1ull << (esz * 8)) - 1;
+
+ for (int i = 0; i < vl; i += esz) {
+ uint64_t x = 0, got = 0, exp = 0;
+
+ memcpy(&x, in + i, esz);
+ memcpy(&got, out + i, esz);
+ if (i < n) {
+ exp = tests[t].ref(x) & mask;
+ }
+ if (got != exp) {
+ fprintf(stderr, "vl %d: %s: byte %d: got 0x%llx, "
+ "expected 0x%llx\n", vl, tests[t].name, i,
+ (unsigned long long)got, (unsigned long long)exp);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int main(void)
+{
+ int err = 0, nvl = 0;
+
+ for (int i = 0; i < MAXVL; i++) {
+ in[i] = 0xa5 ^ (i * 0x37);
+ }
+ /* Zero, saturating and sign-boundary elements in the low 16 bytes. */
+ in[0] = 0x7e; /* sqadd .b overflow */
+ in[2] = in[3] = 0; /* cmeq .h, zero */
+ in[8] = 1; /* uqsub .s underflow */
+ in[9] = in[10] = in[11] = 0;
+ in[12] = 0xfa; in[13] = 0xff; /* uqadd .h overflow */
+
+ for (int vl = 16; vl <= MAXVL; vl *= 2) {
+ if (prctl(PR_SVE_SET_VL, vl, 0, 0, 0, 0) != vl) {
+ continue;
+ }
+ nvl++;
+ for (int t = 0; t < sizeof(tests) / sizeof(tests[0]); t++) {
+ memset(out, 0xee, sizeof(out));
+ tests[t].fn();
+ err |= check(vl, t);
+ }
+ }
+ if (nvl == 0) {
+ fprintf(stderr, "no SVE vector length available\n");
+ return 1;
+ }
+ return err;
+}
diff --git a/tests/tcg/aarch64/meson.build b/tests/tcg/aarch64/meson.build
index 52eb67ae6ace..2033356e3625 100644
--- a/tests/tcg/aarch64/meson.build
+++ b/tests/tcg/aarch64/meson.build
@@ -145,6 +145,7 @@ tests += {
tests += {
'test-826.c': {'cc_feat': 'sve2'},
'sve-while-ptr.c': {'cc_feat': 'sve2'},
+ 'sve-vec-imm.c': {'cc_feat': 'sve2'},
}
# FPRCVT test
--
2.55.0
next prev parent reply other threads:[~2026-10-28 14:35 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-28 14:33 [PATCH v3 0/6] tcg/riscv64: Fix vector immediate handling Philippe Mathieu-Daudé
2026-10-28 14:33 ` [PATCH v3 1/6] tcg/riscv64: Factor encode_vi_raw() out of encode_vi() Philippe Mathieu-Daudé
2026-10-29 12:16 ` Richard Henderson
2026-10-29 18:18 ` Aurelien Jarno
2026-10-28 14:33 ` [PATCH v3 2/6] tcg/riscv64: Use a uimm5 encoder for vector shift immediates Philippe Mathieu-Daudé
2026-10-29 12:16 ` Richard Henderson
2026-10-29 18:18 ` Aurelien Jarno
2026-10-28 14:33 ` [PATCH v3 3/6] tcg/riscv64: Extract elements for vector arithmetic immediates Philippe Mathieu-Daudé
2026-10-29 12:17 ` Richard Henderson
2026-10-29 18:18 ` Aurelien Jarno
2026-10-28 14:33 ` [PATCH v3 4/6] tcg/riscv64: Fix constant handling in vector comparisons and selects Philippe Mathieu-Daudé
2026-10-29 12:17 ` Richard Henderson
2026-10-29 18:31 ` Aurelien Jarno
2026-10-28 14:33 ` [PATCH v3 5/6] tcg/riscv64: Fix logical vector immediate matching and emission Philippe Mathieu-Daudé
2026-10-29 12:20 ` Richard Henderson
2026-10-29 14:12 ` Richard Henderson
2026-10-29 18:33 ` Aurelien Jarno
2026-10-28 14:33 ` Philippe Mathieu-Daudé [this message]
2026-10-29 12:22 ` [PATCH v3 6/6] tests/tcg/aarch64: Add vector immediate regression tests Richard Henderson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261028143330.6518-7-philmd@oss.qualcomm.com \
--to=philmd@oss.qualcomm.com \
--cc=Alistair.Francis@wdc.com \
--cc=aurelien@aurel32.net \
--cc=daniel.barboza@oss.qualcomm.com \
--cc=palmer@dabbelt.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=qemu-riscv@nongnu.org \
--cc=richard.henderson@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.