All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/6] tcg/riscv64: Fix vector immediate handling
@ 2026-10-28 14:33 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é
                   ` (5 more replies)
  0 siblings, 6 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-10-28 14:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-riscv, Daniel Henrique Barboza, Aurelien Jarno,
	Richard Henderson, Alistair Francis, Peter Maydell,
	Palmer Dabbelt, qemu-arm, Philippe Mathieu-Daudé

The riscv64 backend mishandles constant operands of RVV .vi forms:

- logical ops apply the immediate at a stale SEW (wrong results,
  since v9.2);
- arithmetic, compare and select ops encode the whole replicated
  64-bit constant instead of one element;
- shifts take uimm5, but the encoder checks for simm5.

1-2: add a uimm5 encoder for shifts,
3-4: extract one element (vec_imm()) for arithmetic and compare/select,
5: follow rth suggestion of adding a new constraint to pick the smallest
   element size at which the constant replicates as a simm5, and the
   emitter switches SEW to it,
6: AI-generated regression test.

Tested with qemu-aarch64 built for a riscv64 host (debug-TCG), run
under qemu-riscv64 -cpu max: the new test fails or aborts before the
series, and passes with it at every SVE vector length.

[1] https://lore.kernel.org/qemu-devel/20261010174742.3552498-1-aurelien@aurel32.net/
Supersedes: <20261010174742.3552498-1-aurelien@aurel32.net>

Philippe Mathieu-Daudé (6):
  tcg/riscv64: Factor encode_vi_raw() out of encode_vi()
  tcg/riscv64: Use a uimm5 encoder for vector shift immediates
  tcg/riscv64: Extract elements for vector arithmetic immediates
  tcg/riscv64: Fix constant handling in vector comparisons and selects
  tcg/riscv64: Fix logical vector immediate matching and emission
  tests/tcg/aarch64: Add vector immediate regression tests

 tcg/riscv64/tcg-target-con-set.h |   1 +
 tcg/riscv64/tcg-target-con-str.h |   1 +
 tests/tcg/aarch64/sve-vec-imm.c  | 233 +++++++++++++++++++++++++++++++
 tcg/riscv64/tcg-target.c.inc     | 116 ++++++++++++---
 tests/tcg/aarch64/meson.build    |   1 +
 5 files changed, 330 insertions(+), 22 deletions(-)
 create mode 100644 tests/tcg/aarch64/sve-vec-imm.c

-- 
2.55.0



^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v3 1/6] tcg/riscv64: Factor encode_vi_raw() out of encode_vi()
  2026-10-28 14:33 [PATCH v3 0/6] tcg/riscv64: Fix vector immediate handling Philippe Mathieu-Daudé
@ 2026-10-28 14:33 ` 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é
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-10-28 14:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-riscv, Daniel Henrique Barboza, Aurelien Jarno,
	Richard Henderson, Alistair Francis, Peter Maydell,
	Palmer Dabbelt, qemu-arm, Philippe Mathieu-Daudé

Move the OPIVI field layout into encode_vi_raw(), keeping the
simm5 check in encode_vi(). The next commit adds a uimm5 variant
for the vector shift instructions. No functional change.

Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
 tcg/riscv64/tcg-target.c.inc | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
index 03f32c5819f3..712170c1203e 100644
--- a/tcg/riscv64/tcg-target.c.inc
+++ b/tcg/riscv64/tcg-target.c.inc
@@ -534,12 +534,18 @@ static tcg_insn_unit encode_j(RISCVInsn opc, TCGReg rd, tcg_target_long imm)
 
 /* Type-OPIVI */
 
+static tcg_insn_unit encode_vi_raw(RISCVInsn opc, TCGReg rd, unsigned imm5,
+                                   TCGReg vs2, bool vm)
+{
+    return opc | (rd & 0x1f) << 7 | (imm5 & 0x1f) << 15 |
+           (vs2 & 0x1f) << 20 | (vm << 25);
+}
+
 static tcg_insn_unit encode_vi(RISCVInsn opc, TCGReg rd, tcg_target_long imm,
                                TCGReg vs2, bool vm)
 {
     tcg_debug_assert(imm == sextract32(imm, 0, 5));
-    return opc | (rd & 0x1f) << 7 | (imm & 0x1f) << 15 |
-           (vs2 & 0x1f) << 20 | (vm << 25);
+    return encode_vi_raw(opc, rd, imm, vs2, vm);
 }
 
 /* Type-OPIVV/OPMVV/OPIVX/OPMVX, Vector load and store */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 2/6] tcg/riscv64: Use a uimm5 encoder for vector shift immediates
  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-28 14:33 ` 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é
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-10-28 14:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-riscv, Daniel Henrique Barboza, Aurelien Jarno,
	Richard Henderson, Alistair Francis, Peter Maydell,
	Palmer Dabbelt, qemu-arm, Philippe Mathieu-Daudé

RVV shift .vi forms take an unsigned 5-bit immediate, but
encode_vi() checks for simm5, so shift counts 16..31 trip
the debug assertion (and are undefined behaviour in release
builds).

Add encode_vi_u() and use it in tcg_out_vshifti().

Fixes: 006352d69f14 ("tcg/riscv64: Assert immediate in range ...")
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
 tcg/riscv64/tcg-target.c.inc | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
index 712170c1203e..0e749ae296b8 100644
--- a/tcg/riscv64/tcg-target.c.inc
+++ b/tcg/riscv64/tcg-target.c.inc
@@ -541,6 +541,7 @@ static tcg_insn_unit encode_vi_raw(RISCVInsn opc, TCGReg rd, unsigned imm5,
            (vs2 & 0x1f) << 20 | (vm << 25);
 }
 
+/* OPIVI with a signed immediate (simm5). */
 static tcg_insn_unit encode_vi(RISCVInsn opc, TCGReg rd, tcg_target_long imm,
                                TCGReg vs2, bool vm)
 {
@@ -548,6 +549,14 @@ static tcg_insn_unit encode_vi(RISCVInsn opc, TCGReg rd, tcg_target_long imm,
     return encode_vi_raw(opc, rd, imm, vs2, vm);
 }
 
+/* OPIVI with an unsigned immediate (uimm5) */
+static tcg_insn_unit encode_vi_u(RISCVInsn opc, TCGReg rd, unsigned imm,
+                                 TCGReg vs2, bool vm)
+{
+    tcg_debug_assert(imm == extract32(imm, 0, 5));
+    return encode_vi_raw(opc, rd, imm, vs2, vm);
+}
+
 /* Type-OPIVV/OPMVV/OPIVX/OPMVX, Vector load and store */
 
 static tcg_insn_unit encode_v(RISCVInsn opc, TCGReg d, TCGReg s1,
@@ -720,6 +729,12 @@ static void tcg_out_opc_vi(TCGContext *s, RISCVInsn opc,
     tcg_out32(s, encode_vi(opc, vd, imm, vs2, true));
 }
 
+static void tcg_out_opc_vi_u(TCGContext *s, RISCVInsn opc,
+                             TCGReg vd, TCGReg vs2, unsigned imm)
+{
+    tcg_out32(s, encode_vi_u(opc, vd, imm, vs2, true));
+}
+
 static void tcg_out_opc_vv_vi(TCGContext *s, RISCVInsn o_vv, RISCVInsn o_vi,
                               TCGReg vd, TCGReg vs2, TCGArg vi1, int c_vi1)
 {
@@ -1578,7 +1593,7 @@ static void tcg_out_vshifti(TCGContext *s, RISCVInsn opc_vi, RISCVInsn opc_vx,
                              TCGReg dst, TCGReg src, unsigned imm)
 {
     if (imm < 32) {
-        tcg_out_opc_vi(s, opc_vi, dst, src, imm);
+        tcg_out_opc_vi_u(s, opc_vi, dst, src, imm);
     } else {
         tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP0, imm);
         tcg_out_opc_vx(s, opc_vx, dst, src, TCG_REG_TMP0);
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 3/6] tcg/riscv64: Extract elements for vector arithmetic immediates
  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-28 14:33 ` [PATCH v3 2/6] tcg/riscv64: Use a uimm5 encoder for vector shift immediates Philippe Mathieu-Daudé
@ 2026-10-28 14:33 ` 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é
                   ` (2 subsequent siblings)
  5 siblings, 2 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-10-28 14:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-riscv, Daniel Henrique Barboza, Aurelien Jarno,
	Richard Henderson, Alistair Francis, Peter Maydell,
	Palmer Dabbelt, qemu-arm, Philippe Mathieu-Daudé

The .vi emitters for add, reverse sub and saturating ops pass the
whole replicated constant (e.g. 0x0505050505050505) to encode_vi()
instead of a single element. This aborts debug builds on common
vectorized guest code and is undefined behaviour in release builds.

Add vec_imm() to extract the VECE element, and use it.

Fixes: 006352d69f14 ("tcg/riscv64: Assert immediate in range ...")
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
 tcg/riscv64/tcg-target.c.inc | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
index 0e749ae296b8..a3d995e290b7 100644
--- a/tcg/riscv64/tcg-target.c.inc
+++ b/tcg/riscv64/tcg-target.c.inc
@@ -735,6 +735,12 @@ static void tcg_out_opc_vi_u(TCGContext *s, RISCVInsn opc,
     tcg_out32(s, encode_vi_u(opc, vd, imm, vs2, true));
 }
 
+/* Constants are replicated by VECE; extract one element for .vi forms. */
+static int64_t vec_imm(TCGArg arg, unsigned vece)
+{
+    return sextract64(arg, 0, 8 << vece);
+}
+
 static void tcg_out_opc_vv_vi(TCGContext *s, RISCVInsn o_vv, RISCVInsn o_vi,
                               TCGReg vd, TCGReg vs2, TCGArg vi1, int c_vi1)
 {
@@ -2788,12 +2794,13 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
         break;
     case INDEX_op_add_vec:
         set_vtype_len_sew(s, type, vece);
-        tcg_out_opc_vv_vi(s, OPC_VADD_VV, OPC_VADD_VI, a0, a1, a2, c2);
+        tcg_out_opc_vv_vi(s, OPC_VADD_VV, OPC_VADD_VI, a0, a1,
+                          c2 ? vec_imm(a2, vece) : a2, c2);
         break;
     case INDEX_op_sub_vec:
         set_vtype_len_sew(s, type, vece);
         if (const_args[1]) {
-            tcg_out_opc_vi(s, OPC_VRSUB_VI, a0, a2, a1);
+            tcg_out_opc_vi(s, OPC_VRSUB_VI, a0, a2, vec_imm(a1, vece));
         } else {
             tcg_out_opc_vv(s, OPC_VSUB_VV, a0, a1, a2);
         }
@@ -2824,19 +2831,23 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
         break;
     case INDEX_op_ssadd_vec:
         set_vtype_len_sew(s, type, vece);
-        tcg_out_opc_vv_vi(s, OPC_VSADD_VV, OPC_VSADD_VI, a0, a1, a2, c2);
+        tcg_out_opc_vv_vi(s, OPC_VSADD_VV, OPC_VSADD_VI, a0, a1,
+                          c2 ? vec_imm(a2, vece) : a2, c2);
         break;
     case INDEX_op_sssub_vec:
         set_vtype_len_sew(s, type, vece);
-        tcg_out_opc_vv_vi(s, OPC_VSSUB_VV, OPC_VSSUB_VI, a0, a1, a2, c2);
+        tcg_out_opc_vv_vi(s, OPC_VSSUB_VV, OPC_VSSUB_VI, a0, a1,
+                          c2 ? vec_imm(a2, vece) : a2, c2);
         break;
     case INDEX_op_usadd_vec:
         set_vtype_len_sew(s, type, vece);
-        tcg_out_opc_vv_vi(s, OPC_VSADDU_VV, OPC_VSADDU_VI, a0, a1, a2, c2);
+        tcg_out_opc_vv_vi(s, OPC_VSADDU_VV, OPC_VSADDU_VI, a0, a1,
+                          c2 ? vec_imm(a2, vece) : a2, c2);
         break;
     case INDEX_op_ussub_vec:
         set_vtype_len_sew(s, type, vece);
-        tcg_out_opc_vv_vi(s, OPC_VSSUBU_VV, OPC_VSSUBU_VI, a0, a1, a2, c2);
+        tcg_out_opc_vv_vi(s, OPC_VSSUBU_VV, OPC_VSSUBU_VI, a0, a1,
+                          c2 ? vec_imm(a2, vece) : a2, c2);
         break;
     case INDEX_op_smax_vec:
         set_vtype_len_sew(s, type, vece);
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 4/6] tcg/riscv64: Fix constant handling in vector comparisons and selects
  2026-10-28 14:33 [PATCH v3 0/6] tcg/riscv64: Fix vector immediate handling Philippe Mathieu-Daudé
                   ` (2 preceding siblings ...)
  2026-10-28 14:33 ` [PATCH v3 3/6] tcg/riscv64: Extract elements for vector arithmetic immediates Philippe Mathieu-Daudé
@ 2026-10-28 14:33 ` 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-28 14:33 ` [PATCH v3 6/6] tests/tcg/aarch64: Add vector immediate regression tests Philippe Mathieu-Daudé
  5 siblings, 2 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-10-28 14:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-riscv, Daniel Henrique Barboza, Aurelien Jarno,
	Richard Henderson, Alistair Francis, Peter Maydell,
	Palmer Dabbelt, qemu-arm, Philippe Mathieu-Daudé

tcg_out_cmpsel() takes constants as TCGReg and passes them to the
encoders unextracted. In a release build, "cmlt v0.8h, #0" emitted
the illegal instruction 0xffffb057.

Use TCGArg for these operands and extract the element with
vec_imm() before encoding, including before the LT/GE adjustment.

Fixes: 006352d69f14 ("tcg/riscv64: Assert immediate in range ...")
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
 tcg/riscv64/tcg-target.c.inc | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
index a3d995e290b7..168932711796 100644
--- a/tcg/riscv64/tcg-target.c.inc
+++ b/tcg/riscv64/tcg-target.c.inc
@@ -1555,9 +1555,9 @@ static void tcg_out_cltz(TCGContext *s, TCGType type, RISCVInsn insn,
 
 static void tcg_out_cmpsel(TCGContext *s, TCGType type, unsigned vece,
                            TCGCond cond, TCGReg ret,
-                           TCGReg cmp1, TCGReg cmp2, bool c_cmp2,
-                           TCGReg val1, bool c_val1,
-                           TCGReg val2, bool c_val2)
+                           TCGReg cmp1, TCGArg cmp2, bool c_cmp2,
+                           TCGArg val1, bool c_val1,
+                           TCGArg val2, bool c_val2)
 {
     set_vtype_len_sew(s, type, vece);
 
@@ -1574,7 +1574,7 @@ static void tcg_out_cmpsel(TCGContext *s, TCGType type, unsigned vece,
     /* Perform the comparison into V0 mask. */
     if (c_cmp2) {
         tcg_out_opc_vi(s, tcg_cmpcond_to_rvv_vi[cond].op, TCG_REG_V0, cmp1,
-                       cmp2 - tcg_cmpcond_to_rvv_vi[cond].adjust);
+                       vec_imm(cmp2, vece) - tcg_cmpcond_to_rvv_vi[cond].adjust);
     } else if (tcg_cmpcond_to_rvv_vv[cond].swap) {
         tcg_out_opc_vv(s, tcg_cmpcond_to_rvv_vv[cond].op,
                        TCG_REG_V0, cmp2, cmp1);
@@ -1584,11 +1584,12 @@ static void tcg_out_cmpsel(TCGContext *s, TCGType type, unsigned vece,
     }
     if (c_val1) {
         if (c_val2) {
-            tcg_out_opc_vi(s, OPC_VMV_V_I, ret, 0, val2);
+            tcg_out_opc_vi(s, OPC_VMV_V_I, ret, 0, vec_imm(val2, vece));
             val2 = ret;
         }
         /* vd[i] == v0.mask[i] ? imm : vs2[i] */
-        tcg_out_opc_vim_mask(s, OPC_VMERGE_VIM, ret, val2, val1);
+        tcg_out_opc_vim_mask(s, OPC_VMERGE_VIM, ret, val2,
+                             vec_imm(val1, vece));
     } else {
         /* vd[i] == v0.mask[i] ? vs1[i] : vs2[i] */
         tcg_out_opc_vvm_mask(s, OPC_VMERGE_VVM, ret, val2, val1);
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 5/6] tcg/riscv64: Fix logical vector immediate matching and emission
  2026-10-28 14:33 [PATCH v3 0/6] tcg/riscv64: Fix vector immediate handling Philippe Mathieu-Daudé
                   ` (3 preceding siblings ...)
  2026-10-28 14:33 ` [PATCH v3 4/6] tcg/riscv64: Fix constant handling in vector comparisons and selects Philippe Mathieu-Daudé
@ 2026-10-28 14:33 ` Philippe Mathieu-Daudé
  2026-10-29 12:20   ` Richard Henderson
  2026-10-29 18:33   ` Aurelien Jarno
  2026-10-28 14:33 ` [PATCH v3 6/6] tests/tcg/aarch64: Add vector immediate regression tests Philippe Mathieu-Daudé
  5 siblings, 2 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-10-28 14:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-riscv, Daniel Henrique Barboza, Aurelien Jarno,
	Richard Henderson, Alistair Francis, Peter Maydell,
	Palmer Dabbelt, qemu-arm, Philippe Mathieu-Daudé,
	qemu-stable

and/or/xor_vec always have VECE 0, yet their constant was matched
as a byte element and applied at the stale SEW of the previous op:
"bic v4.8h, #0xf0" became "vand.vi ..., 15".

Add the 'N' constraint: use the smallest element size at which the
constant replicates, if that element fits simm5, and switch SEW to
it. A wider element can't fit when the smallest doesn't: its upper
half repeats the smaller element, which would then be 0 or -1.

Cc: qemu-stable@nongnu.org
Fixes: 5a63f5998791 ("tcg/riscv: Add support for basic vector opcodes")
Reported-by: Aurelien Jarno <aurelien@aurel32.net>
Suggested-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
 tcg/riscv64/tcg-target-con-set.h |  1 +
 tcg/riscv64/tcg-target-con-str.h |  1 +
 tcg/riscv64/tcg-target.c.inc     | 53 +++++++++++++++++++++++++++-----
 3 files changed, 48 insertions(+), 7 deletions(-)

diff --git a/tcg/riscv64/tcg-target-con-set.h b/tcg/riscv64/tcg-target-con-set.h
index 0fc26d3f98b4..9b4e219fac16 100644
--- a/tcg/riscv64/tcg-target-con-set.h
+++ b/tcg/riscv64/tcg-target-con-set.h
@@ -26,4 +26,5 @@ C_O1_I2(v, v, v)
 C_O1_I2(v, vK, v)
 C_O1_I2(v, v, vK)
 C_O1_I2(v, v, vL)
+C_O1_I2(v, v, vN)
 C_O1_I4(v, v, vL, vK, vK)
diff --git a/tcg/riscv64/tcg-target-con-str.h b/tcg/riscv64/tcg-target-con-str.h
index c04e15ddfa3c..d7e8b2ce4f2f 100644
--- a/tcg/riscv64/tcg-target-con-str.h
+++ b/tcg/riscv64/tcg-target-con-str.h
@@ -19,3 +19,4 @@ CONST('I', TCG_CT_CONST_S12)
 CONST('K', TCG_CT_CONST_S5)
 CONST('L', TCG_CT_CONST_CMP_VI)
 CONST('M', TCG_CT_CONST_M12)
+CONST('N', TCG_CT_CONST_LOGICAL_VI)
diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
index 168932711796..4faf7ff36e07 100644
--- a/tcg/riscv64/tcg-target.c.inc
+++ b/tcg/riscv64/tcg-target.c.inc
@@ -116,6 +116,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot)
 #define TCG_CT_CONST_M12     0x200
 #define TCG_CT_CONST_S5      0x400
 #define TCG_CT_CONST_CMP_VI  0x800
+#define TCG_CT_CONST_LOGICAL_VI 0x1000
 
 #define ALL_GENERAL_REGS   MAKE_64BIT_MASK(0, 32)
 #define ALL_VECTOR_REGS    MAKE_64BIT_MASK(32, 32)
@@ -384,6 +385,22 @@ static const struct {
     [TCG_COND_GEU] = { OPC_VMSGTU_VI,   1, 16, true  },
 };
 
+/*
+ * Return the element size at which VAL is a replicated simm5,
+ * or -1 if there is none.  Used for vector logical ops, whose
+ * VECE is not meaningful.
+ */
+static int vec_logical_immediate_vece(int64_t val)
+{
+    for (int e = MO_8; e <= MO_64; e++) {
+        if (val == dup_const(e, val)) {
+            int64_t x = sextract64(val, 0, 8 << e);
+            return x >= -0x10 && x <= 0x0f ? e : -1;
+        }
+    }
+    g_assert_not_reached();
+}
+
 /* test if a constant matches the constraint */
 static bool tcg_target_const_match(int64_t val, int ct,
                                    TCGType type, TCGCond cond, int vece)
@@ -391,6 +408,10 @@ static bool tcg_target_const_match(int64_t val, int ct,
     if (ct & TCG_CT_CONST) {
         return 1;
     }
+    if ((ct & TCG_CT_CONST_LOGICAL_VI) &&
+        vec_logical_immediate_vece(val) >= 0) {
+        return true;
+    }
     if (type >= TCG_TYPE_V64) {
         /* Val is replicated by VECE; extract the highest element. */
         val >>= (-8 << vece) & 63;
@@ -2769,6 +2790,23 @@ static const TCGOutOpStore outop_st = {
 };
 
 
+static void tcg_out_opc_vv_vi_logical(TCGContext *s, TCGType type,
+                                      RISCVInsn o_vv, RISCVInsn o_vi,
+                                      TCGReg vd, TCGReg vs2,
+                                      TCGArg vi1, int c_vi1)
+{
+    if (c_vi1) {
+        int vece = vec_logical_immediate_vece(vi1);
+
+        tcg_debug_assert(vece >= 0);
+        set_vtype_len_sew(s, type, vece);
+        tcg_out_opc_vi(s, o_vi, vd, vs2, vec_imm(vi1, vece));
+    } else {
+        set_vtype_len(s, type);
+        tcg_out_opc_vv(s, o_vv, vd, vs2, vi1);
+    }
+}
+
 static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
                            unsigned vecl, unsigned vece,
                            const TCGArg args[TCG_MAX_OP_ARGS],
@@ -2807,16 +2845,16 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
         }
         break;
     case INDEX_op_and_vec:
-        set_vtype_len(s, type);
-        tcg_out_opc_vv_vi(s, OPC_VAND_VV, OPC_VAND_VI, a0, a1, a2, c2);
+        tcg_out_opc_vv_vi_logical(s, type, OPC_VAND_VV, OPC_VAND_VI,
+                                  a0, a1, a2, c2);
         break;
     case INDEX_op_or_vec:
-        set_vtype_len(s, type);
-        tcg_out_opc_vv_vi(s, OPC_VOR_VV, OPC_VOR_VI, a0, a1, a2, c2);
+        tcg_out_opc_vv_vi_logical(s, type, OPC_VOR_VV, OPC_VOR_VI,
+                                  a0, a1, a2, c2);
         break;
     case INDEX_op_xor_vec:
-        set_vtype_len(s, type);
-        tcg_out_opc_vv_vi(s, OPC_VXOR_VV, OPC_VXOR_VI, a0, a1, a2, c2);
+        tcg_out_opc_vv_vi_logical(s, type, OPC_VXOR_VV, OPC_VXOR_VI,
+                                  a0, a1, a2, c2);
         break;
     case INDEX_op_not_vec:
         set_vtype_len(s, type);
@@ -3008,10 +3046,11 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags)
     case INDEX_op_sari_vec:
     case INDEX_op_rotli_vec:
         return C_O1_I1(v, v);
-    case INDEX_op_add_vec:
     case INDEX_op_and_vec:
     case INDEX_op_or_vec:
     case INDEX_op_xor_vec:
+        return C_O1_I2(v, v, vN);
+    case INDEX_op_add_vec:
     case INDEX_op_ssadd_vec:
     case INDEX_op_sssub_vec:
     case INDEX_op_usadd_vec:
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 6/6] tests/tcg/aarch64: Add vector immediate regression tests
  2026-10-28 14:33 [PATCH v3 0/6] tcg/riscv64: Fix vector immediate handling Philippe Mathieu-Daudé
                   ` (4 preceding siblings ...)
  2026-10-28 14:33 ` [PATCH v3 5/6] tcg/riscv64: Fix logical vector immediate matching and emission Philippe Mathieu-Daudé
@ 2026-10-28 14:33 ` Philippe Mathieu-Daudé
  2026-10-29 12:22   ` Richard Henderson
  5 siblings, 1 reply; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-10-28 14:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-riscv, Daniel Henrique Barboza, Aurelien Jarno,
	Richard Henderson, Alistair Francis, Peter Maydell,
	Palmer Dabbelt, qemu-arm, Philippe Mathieu-Daudé

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



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 1/6] tcg/riscv64: Factor encode_vi_raw() out of encode_vi()
  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
  1 sibling, 0 replies; 21+ messages in thread
From: Richard Henderson @ 2026-10-29 12:16 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel
  Cc: qemu-riscv, Daniel Henrique Barboza, Aurelien Jarno,
	Alistair Francis, Peter Maydell, Palmer Dabbelt, qemu-arm

On 10/28/26 09:33, Philippe Mathieu-Daudé wrote:
> Move the OPIVI field layout into encode_vi_raw(), keeping the
> simm5 check in encode_vi(). The next commit adds a uimm5 variant
> for the vector shift instructions. No functional change.
> 
> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> ---
>   tcg/riscv64/tcg-target.c.inc | 10 ++++++++--
>   1 file changed, 8 insertions(+), 2 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/6] tcg/riscv64: Use a uimm5 encoder for vector shift immediates
  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
  1 sibling, 0 replies; 21+ messages in thread
From: Richard Henderson @ 2026-10-29 12:16 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel
  Cc: qemu-riscv, Daniel Henrique Barboza, Aurelien Jarno,
	Alistair Francis, Peter Maydell, Palmer Dabbelt, qemu-arm

On 10/28/26 09:33, Philippe Mathieu-Daudé wrote:
> RVV shift .vi forms take an unsigned 5-bit immediate, but
> encode_vi() checks for simm5, so shift counts 16..31 trip
> the debug assertion (and are undefined behaviour in release
> builds).
> 
> Add encode_vi_u() and use it in tcg_out_vshifti().
> 
> Fixes: 006352d69f14 ("tcg/riscv64: Assert immediate in range ...")
> Signed-off-by: Philippe Mathieu-Daudé<philmd@oss.qualcomm.com>
> ---
>   tcg/riscv64/tcg-target.c.inc | 17 ++++++++++++++++-
>   1 file changed, 16 insertions(+), 1 deletion(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 3/6] tcg/riscv64: Extract elements for vector arithmetic immediates
  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
  1 sibling, 0 replies; 21+ messages in thread
From: Richard Henderson @ 2026-10-29 12:17 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel
  Cc: qemu-riscv, Daniel Henrique Barboza, Aurelien Jarno,
	Alistair Francis, Peter Maydell, Palmer Dabbelt, qemu-arm

On 10/28/26 09:33, Philippe Mathieu-Daudé wrote:
> The .vi emitters for add, reverse sub and saturating ops pass the
> whole replicated constant (e.g. 0x0505050505050505) to encode_vi()
> instead of a single element. This aborts debug builds on common
> vectorized guest code and is undefined behaviour in release builds.
> 
> Add vec_imm() to extract the VECE element, and use it.
> 
> Fixes: 006352d69f14 ("tcg/riscv64: Assert immediate in range ...")
> Signed-off-by: Philippe Mathieu-Daudé<philmd@oss.qualcomm.com>
> ---
>   tcg/riscv64/tcg-target.c.inc | 23 +++++++++++++++++------
>   1 file changed, 17 insertions(+), 6 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 4/6] tcg/riscv64: Fix constant handling in vector comparisons and selects
  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
  1 sibling, 0 replies; 21+ messages in thread
From: Richard Henderson @ 2026-10-29 12:17 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel
  Cc: qemu-riscv, Daniel Henrique Barboza, Aurelien Jarno,
	Alistair Francis, Peter Maydell, Palmer Dabbelt, qemu-arm

On 10/28/26 09:33, Philippe Mathieu-Daudé wrote:
> tcg_out_cmpsel() takes constants as TCGReg and passes them to the
> encoders unextracted. In a release build, "cmlt v0.8h, #0" emitted
> the illegal instruction 0xffffb057.
> 
> Use TCGArg for these operands and extract the element with
> vec_imm() before encoding, including before the LT/GE adjustment.
> 
> Fixes: 006352d69f14 ("tcg/riscv64: Assert immediate in range ...")
> Signed-off-by: Philippe Mathieu-Daudé<philmd@oss.qualcomm.com>
> ---
>   tcg/riscv64/tcg-target.c.inc | 13 +++++++------
>   1 file changed, 7 insertions(+), 6 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 5/6] tcg/riscv64: Fix logical vector immediate matching and emission
  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
  1 sibling, 1 reply; 21+ messages in thread
From: Richard Henderson @ 2026-10-29 12:20 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel
  Cc: qemu-riscv, Daniel Henrique Barboza, Aurelien Jarno,
	Alistair Francis, Peter Maydell, Palmer Dabbelt, qemu-arm,
	qemu-stable

On 10/28/26 09:33, Philippe Mathieu-Daudé wrote:
> and/or/xor_vec always have VECE 0, yet their constant was matched
> as a byte element and applied at the stale SEW of the previous op:
> "bic v4.8h, #0xf0" became "vand.vi ..., 15".
> 
> Add the 'N' constraint: use the smallest element size at which the
> constant replicates, if that element fits simm5, and switch SEW to
> it. A wider element can't fit when the smallest doesn't: its upper
> half repeats the smaller element, which would then be 0 or -1.
> 
> Cc: qemu-stable@nongnu.org
> Fixes: 5a63f5998791 ("tcg/riscv: Add support for basic vector opcodes")
> Reported-by: Aurelien Jarno <aurelien@aurel32.net>
> Suggested-by: Richard Henderson <richard.henderson@linaro.org>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> ---
>   tcg/riscv64/tcg-target-con-set.h |  1 +
>   tcg/riscv64/tcg-target-con-str.h |  1 +
>   tcg/riscv64/tcg-target.c.inc     | 53 +++++++++++++++++++++++++++-----
>   3 files changed, 48 insertions(+), 7 deletions(-)
> 
> diff --git a/tcg/riscv64/tcg-target-con-set.h b/tcg/riscv64/tcg-target-con-set.h
> index 0fc26d3f98b4..9b4e219fac16 100644
> --- a/tcg/riscv64/tcg-target-con-set.h
> +++ b/tcg/riscv64/tcg-target-con-set.h
> @@ -26,4 +26,5 @@ C_O1_I2(v, v, v)
>   C_O1_I2(v, vK, v)
>   C_O1_I2(v, v, vK)
>   C_O1_I2(v, v, vL)
> +C_O1_I2(v, v, vN)
>   C_O1_I4(v, v, vL, vK, vK)
> diff --git a/tcg/riscv64/tcg-target-con-str.h b/tcg/riscv64/tcg-target-con-str.h
> index c04e15ddfa3c..d7e8b2ce4f2f 100644
> --- a/tcg/riscv64/tcg-target-con-str.h
> +++ b/tcg/riscv64/tcg-target-con-str.h
> @@ -19,3 +19,4 @@ CONST('I', TCG_CT_CONST_S12)
>   CONST('K', TCG_CT_CONST_S5)
>   CONST('L', TCG_CT_CONST_CMP_VI)
>   CONST('M', TCG_CT_CONST_M12)
> +CONST('N', TCG_CT_CONST_LOGICAL_VI)
> diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
> index 168932711796..4faf7ff36e07 100644
> --- a/tcg/riscv64/tcg-target.c.inc
> +++ b/tcg/riscv64/tcg-target.c.inc
> @@ -116,6 +116,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot)
>   #define TCG_CT_CONST_M12     0x200
>   #define TCG_CT_CONST_S5      0x400
>   #define TCG_CT_CONST_CMP_VI  0x800
> +#define TCG_CT_CONST_LOGICAL_VI 0x1000
>   
>   #define ALL_GENERAL_REGS   MAKE_64BIT_MASK(0, 32)
>   #define ALL_VECTOR_REGS    MAKE_64BIT_MASK(32, 32)
> @@ -384,6 +385,22 @@ static const struct {
>       [TCG_COND_GEU] = { OPC_VMSGTU_VI,   1, 16, true  },
>   };
>   
> +/*
> + * Return the element size at which VAL is a replicated simm5,
> + * or -1 if there is none.  Used for vector logical ops, whose
> + * VECE is not meaningful.
> + */
> +static int vec_logical_immediate_vece(int64_t val)
> +{
> +    for (int e = MO_8; e <= MO_64; e++) {
> +        if (val == dup_const(e, val)) {
> +            int64_t x = sextract64(val, 0, 8 << e);
> +            return x >= -0x10 && x <= 0x0f ? e : -1;
> +        }
> +    }
> +    g_assert_not_reached();
> +}

This assert can trigger...

> +
>   /* test if a constant matches the constraint */
>   static bool tcg_target_const_match(int64_t val, int ct,
>                                      TCGType type, TCGCond cond, int vece)
> @@ -391,6 +408,10 @@ static bool tcg_target_const_match(int64_t val, int ct,
>       if (ct & TCG_CT_CONST) {
>           return 1;
>       }
> +    if ((ct & TCG_CT_CONST_LOGICAL_VI) &&
> +        vec_logical_immediate_vece(val) >= 0) {
> +        return true;
> +    }

... here.  Return -1 instead so...

>       if (type >= TCG_TYPE_V64) {
>           /* Val is replicated by VECE; extract the highest element. */
>           val >>= (-8 << vece) & 63;
> @@ -2769,6 +2790,23 @@ static const TCGOutOpStore outop_st = {
>   };
>   
>   
> +static void tcg_out_opc_vv_vi_logical(TCGContext *s, TCGType type,
> +                                      RISCVInsn o_vv, RISCVInsn o_vi,
> +                                      TCGReg vd, TCGReg vs2,
> +                                      TCGArg vi1, int c_vi1)
> +{
> +    if (c_vi1) {
> +        int vece = vec_logical_immediate_vece(vi1);
> +
> +        tcg_debug_assert(vece >= 0);

... it is properly handled by this assert anyway.


r~


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 6/6] tests/tcg/aarch64: Add vector immediate regression tests
  2026-10-28 14:33 ` [PATCH v3 6/6] tests/tcg/aarch64: Add vector immediate regression tests Philippe Mathieu-Daudé
@ 2026-10-29 12:22   ` Richard Henderson
  0 siblings, 0 replies; 21+ messages in thread
From: Richard Henderson @ 2026-10-29 12:22 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel
  Cc: qemu-riscv, Daniel Henrique Barboza, Aurelien Jarno,
	Alistair Francis, Peter Maydell, Palmer Dabbelt, qemu-arm

On 10/28/26 09:33, Philippe Mathieu-Daudé wrote:
> 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

Acked-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 5/6] tcg/riscv64: Fix logical vector immediate matching and emission
  2026-10-29 12:20   ` Richard Henderson
@ 2026-10-29 14:12     ` Richard Henderson
  0 siblings, 0 replies; 21+ messages in thread
From: Richard Henderson @ 2026-10-29 14:12 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel
  Cc: qemu-riscv, Daniel Henrique Barboza, Aurelien Jarno,
	Alistair Francis, Peter Maydell, Palmer Dabbelt, qemu-arm,
	qemu-stable

On 10/29/26 07:20, Richard Henderson wrote:
> On 10/28/26 09:33, Philippe Mathieu-Daudé wrote:
>> and/or/xor_vec always have VECE 0, yet their constant was matched
>> as a byte element and applied at the stale SEW of the previous op:
>> "bic v4.8h, #0xf0" became "vand.vi ..., 15".
>>
>> Add the 'N' constraint: use the smallest element size at which the
>> constant replicates, if that element fits simm5, and switch SEW to
>> it. A wider element can't fit when the smallest doesn't: its upper
>> half repeats the smaller element, which would then be 0 or -1.
>>
>> Cc: qemu-stable@nongnu.org
>> Fixes: 5a63f5998791 ("tcg/riscv: Add support for basic vector opcodes")
>> Reported-by: Aurelien Jarno <aurelien@aurel32.net>
>> Suggested-by: Richard Henderson <richard.henderson@linaro.org>
>> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
>> ---
>>   tcg/riscv64/tcg-target-con-set.h |  1 +
>>   tcg/riscv64/tcg-target-con-str.h |  1 +
>>   tcg/riscv64/tcg-target.c.inc     | 53 +++++++++++++++++++++++++++-----
>>   3 files changed, 48 insertions(+), 7 deletions(-)
>>
>> diff --git a/tcg/riscv64/tcg-target-con-set.h b/tcg/riscv64/tcg- 
>> target-con-set.h
>> index 0fc26d3f98b4..9b4e219fac16 100644
>> --- a/tcg/riscv64/tcg-target-con-set.h
>> +++ b/tcg/riscv64/tcg-target-con-set.h
>> @@ -26,4 +26,5 @@ C_O1_I2(v, v, v)
>>   C_O1_I2(v, vK, v)
>>   C_O1_I2(v, v, vK)
>>   C_O1_I2(v, v, vL)
>> +C_O1_I2(v, v, vN)
>>   C_O1_I4(v, v, vL, vK, vK)
>> diff --git a/tcg/riscv64/tcg-target-con-str.h b/tcg/riscv64/tcg- 
>> target-con-str.h
>> index c04e15ddfa3c..d7e8b2ce4f2f 100644
>> --- a/tcg/riscv64/tcg-target-con-str.h
>> +++ b/tcg/riscv64/tcg-target-con-str.h
>> @@ -19,3 +19,4 @@ CONST('I', TCG_CT_CONST_S12)
>>   CONST('K', TCG_CT_CONST_S5)
>>   CONST('L', TCG_CT_CONST_CMP_VI)
>>   CONST('M', TCG_CT_CONST_M12)
>> +CONST('N', TCG_CT_CONST_LOGICAL_VI)
>> diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
>> index 168932711796..4faf7ff36e07 100644
>> --- a/tcg/riscv64/tcg-target.c.inc
>> +++ b/tcg/riscv64/tcg-target.c.inc
>> @@ -116,6 +116,7 @@ static TCGReg 
>> tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot)
>>   #define TCG_CT_CONST_M12     0x200
>>   #define TCG_CT_CONST_S5      0x400
>>   #define TCG_CT_CONST_CMP_VI  0x800
>> +#define TCG_CT_CONST_LOGICAL_VI 0x1000
>>   #define ALL_GENERAL_REGS   MAKE_64BIT_MASK(0, 32)
>>   #define ALL_VECTOR_REGS    MAKE_64BIT_MASK(32, 32)
>> @@ -384,6 +385,22 @@ static const struct {
>>       [TCG_COND_GEU] = { OPC_VMSGTU_VI,   1, 16, true  },
>>   };
>> +/*
>> + * Return the element size at which VAL is a replicated simm5,
>> + * or -1 if there is none.  Used for vector logical ops, whose
>> + * VECE is not meaningful.
>> + */
>> +static int vec_logical_immediate_vece(int64_t val)
>> +{
>> +    for (int e = MO_8; e <= MO_64; e++) {
>> +        if (val == dup_const(e, val)) {
>> +            int64_t x = sextract64(val, 0, 8 << e);
>> +            return x >= -0x10 && x <= 0x0f ? e : -1;
>> +        }
>> +    }
>> +    g_assert_not_reached();
>> +}
> 
> This assert can trigger...

Bah.  No it can't.  Because of course val == dup_const(MO_64, val) is 
always true.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 1/6] tcg/riscv64: Factor encode_vi_raw() out of encode_vi()
  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
  1 sibling, 0 replies; 21+ messages in thread
From: Aurelien Jarno @ 2026-10-29 18:18 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: qemu-devel, qemu-riscv, Daniel Henrique Barboza,
	Richard Henderson, Alistair Francis, Peter Maydell,
	Palmer Dabbelt, qemu-arm

On 2026-10-28 15:33, Philippe Mathieu-Daudé wrote:
> Move the OPIVI field layout into encode_vi_raw(), keeping the
> simm5 check in encode_vi(). The next commit adds a uimm5 variant
> for the vector shift instructions. No functional change.
> 
> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> ---
>  tcg/riscv64/tcg-target.c.inc | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
> index 03f32c5819f3..712170c1203e 100644
> --- a/tcg/riscv64/tcg-target.c.inc
> +++ b/tcg/riscv64/tcg-target.c.inc
> @@ -534,12 +534,18 @@ static tcg_insn_unit encode_j(RISCVInsn opc, TCGReg rd, tcg_target_long imm)
>  
>  /* Type-OPIVI */
>  
> +static tcg_insn_unit encode_vi_raw(RISCVInsn opc, TCGReg rd, unsigned imm5,
> +                                   TCGReg vs2, bool vm)
> +{
> +    return opc | (rd & 0x1f) << 7 | (imm5 & 0x1f) << 15 |
> +           (vs2 & 0x1f) << 20 | (vm << 25);
> +}
> +
>  static tcg_insn_unit encode_vi(RISCVInsn opc, TCGReg rd, tcg_target_long imm,
>                                 TCGReg vs2, bool vm)
>  {
>      tcg_debug_assert(imm == sextract32(imm, 0, 5));
> -    return opc | (rd & 0x1f) << 7 | (imm & 0x1f) << 15 |
> -           (vs2 & 0x1f) << 20 | (vm << 25);
> +    return encode_vi_raw(opc, rd, imm, vs2, vm);
>  }
>  
>  /* Type-OPIVV/OPMVV/OPIVX/OPMVX, Vector load and store */

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                     http://aurel32.net


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/6] tcg/riscv64: Use a uimm5 encoder for vector shift immediates
  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
  1 sibling, 0 replies; 21+ messages in thread
From: Aurelien Jarno @ 2026-10-29 18:18 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: qemu-devel, qemu-riscv, Daniel Henrique Barboza,
	Richard Henderson, Alistair Francis, Peter Maydell,
	Palmer Dabbelt, qemu-arm

On 2026-10-28 15:33, Philippe Mathieu-Daudé wrote:
> RVV shift .vi forms take an unsigned 5-bit immediate, but
> encode_vi() checks for simm5, so shift counts 16..31 trip
> the debug assertion (and are undefined behaviour in release
> builds).
> 
> Add encode_vi_u() and use it in tcg_out_vshifti().
> 
> Fixes: 006352d69f14 ("tcg/riscv64: Assert immediate in range ...")
> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> ---
>  tcg/riscv64/tcg-target.c.inc | 17 ++++++++++++++++-
>  1 file changed, 16 insertions(+), 1 deletion(-)
> 
> diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
> index 712170c1203e..0e749ae296b8 100644
> --- a/tcg/riscv64/tcg-target.c.inc
> +++ b/tcg/riscv64/tcg-target.c.inc
> @@ -541,6 +541,7 @@ static tcg_insn_unit encode_vi_raw(RISCVInsn opc, TCGReg rd, unsigned imm5,
>             (vs2 & 0x1f) << 20 | (vm << 25);
>  }
>  
> +/* OPIVI with a signed immediate (simm5). */
>  static tcg_insn_unit encode_vi(RISCVInsn opc, TCGReg rd, tcg_target_long imm,
>                                 TCGReg vs2, bool vm)
>  {
> @@ -548,6 +549,14 @@ static tcg_insn_unit encode_vi(RISCVInsn opc, TCGReg rd, tcg_target_long imm,
>      return encode_vi_raw(opc, rd, imm, vs2, vm);
>  }
>  
> +/* OPIVI with an unsigned immediate (uimm5) */
> +static tcg_insn_unit encode_vi_u(RISCVInsn opc, TCGReg rd, unsigned imm,
> +                                 TCGReg vs2, bool vm)
> +{
> +    tcg_debug_assert(imm == extract32(imm, 0, 5));
> +    return encode_vi_raw(opc, rd, imm, vs2, vm);
> +}
> +
>  /* Type-OPIVV/OPMVV/OPIVX/OPMVX, Vector load and store */
>  
>  static tcg_insn_unit encode_v(RISCVInsn opc, TCGReg d, TCGReg s1,
> @@ -720,6 +729,12 @@ static void tcg_out_opc_vi(TCGContext *s, RISCVInsn opc,
>      tcg_out32(s, encode_vi(opc, vd, imm, vs2, true));
>  }
>  
> +static void tcg_out_opc_vi_u(TCGContext *s, RISCVInsn opc,
> +                             TCGReg vd, TCGReg vs2, unsigned imm)
> +{
> +    tcg_out32(s, encode_vi_u(opc, vd, imm, vs2, true));
> +}
> +
>  static void tcg_out_opc_vv_vi(TCGContext *s, RISCVInsn o_vv, RISCVInsn o_vi,
>                                TCGReg vd, TCGReg vs2, TCGArg vi1, int c_vi1)
>  {
> @@ -1578,7 +1593,7 @@ static void tcg_out_vshifti(TCGContext *s, RISCVInsn opc_vi, RISCVInsn opc_vx,
>                               TCGReg dst, TCGReg src, unsigned imm)
>  {
>      if (imm < 32) {
> -        tcg_out_opc_vi(s, opc_vi, dst, src, imm);
> +        tcg_out_opc_vi_u(s, opc_vi, dst, src, imm);
>      } else {
>          tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP0, imm);
>          tcg_out_opc_vx(s, opc_vx, dst, src, TCG_REG_TMP0);

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                     http://aurel32.net


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 3/6] tcg/riscv64: Extract elements for vector arithmetic immediates
  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-30  8:05     ` Philippe Mathieu-Daudé
  1 sibling, 1 reply; 21+ messages in thread
From: Aurelien Jarno @ 2026-10-29 18:18 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: qemu-devel, qemu-riscv, Daniel Henrique Barboza,
	Richard Henderson, Alistair Francis, Peter Maydell,
	Palmer Dabbelt, qemu-arm

On 2026-10-28 15:33, Philippe Mathieu-Daudé wrote:
> The .vi emitters for add, reverse sub and saturating ops pass the
> whole replicated constant (e.g. 0x0505050505050505) to encode_vi()
> instead of a single element. This aborts debug builds on common
> vectorized guest code and is undefined behaviour in release builds.
> 
> Add vec_imm() to extract the VECE element, and use it.
> 
> Fixes: 006352d69f14 ("tcg/riscv64: Assert immediate in range ...")
> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> ---
>  tcg/riscv64/tcg-target.c.inc | 23 +++++++++++++++++------
>  1 file changed, 17 insertions(+), 6 deletions(-)
> 
> diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
> index 0e749ae296b8..a3d995e290b7 100644
> --- a/tcg/riscv64/tcg-target.c.inc
> +++ b/tcg/riscv64/tcg-target.c.inc
> @@ -735,6 +735,12 @@ static void tcg_out_opc_vi_u(TCGContext *s, RISCVInsn opc,
>      tcg_out32(s, encode_vi_u(opc, vd, imm, vs2, true));
>  }
>  
> +/* Constants are replicated by VECE; extract one element for .vi forms. */
> +static int64_t vec_imm(TCGArg arg, unsigned vece)
> +{
> +    return sextract64(arg, 0, 8 << vece);
> +}
> +
>  static void tcg_out_opc_vv_vi(TCGContext *s, RISCVInsn o_vv, RISCVInsn o_vi,
>                                TCGReg vd, TCGReg vs2, TCGArg vi1, int c_vi1)
>  {
> @@ -2788,12 +2794,13 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
>          break;
>      case INDEX_op_add_vec:
>          set_vtype_len_sew(s, type, vece);
> -        tcg_out_opc_vv_vi(s, OPC_VADD_VV, OPC_VADD_VI, a0, a1, a2, c2);
> +        tcg_out_opc_vv_vi(s, OPC_VADD_VV, OPC_VADD_VI, a0, a1,
> +                          c2 ? vec_imm(a2, vece) : a2, c2);
>          break;
>      case INDEX_op_sub_vec:
>          set_vtype_len_sew(s, type, vece);
>          if (const_args[1]) {
> -            tcg_out_opc_vi(s, OPC_VRSUB_VI, a0, a2, a1);
> +            tcg_out_opc_vi(s, OPC_VRSUB_VI, a0, a2, vec_imm(a1, vece));
>          } else {
>              tcg_out_opc_vv(s, OPC_VSUB_VV, a0, a1, a2);
>          }
> @@ -2824,19 +2831,23 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
>          break;
>      case INDEX_op_ssadd_vec:
>          set_vtype_len_sew(s, type, vece);
> -        tcg_out_opc_vv_vi(s, OPC_VSADD_VV, OPC_VSADD_VI, a0, a1, a2, c2);
> +        tcg_out_opc_vv_vi(s, OPC_VSADD_VV, OPC_VSADD_VI, a0, a1,
> +                          c2 ? vec_imm(a2, vece) : a2, c2);
>          break;
>      case INDEX_op_sssub_vec:
>          set_vtype_len_sew(s, type, vece);
> -        tcg_out_opc_vv_vi(s, OPC_VSSUB_VV, OPC_VSSUB_VI, a0, a1, a2, c2);
> +        tcg_out_opc_vv_vi(s, OPC_VSSUB_VV, OPC_VSSUB_VI, a0, a1,
> +                          c2 ? vec_imm(a2, vece) : a2, c2);
>          break;
>      case INDEX_op_usadd_vec:
>          set_vtype_len_sew(s, type, vece);
> -        tcg_out_opc_vv_vi(s, OPC_VSADDU_VV, OPC_VSADDU_VI, a0, a1, a2, c2);
> +        tcg_out_opc_vv_vi(s, OPC_VSADDU_VV, OPC_VSADDU_VI, a0, a1,
> +                          c2 ? vec_imm(a2, vece) : a2, c2);
>          break;
>      case INDEX_op_ussub_vec:
>          set_vtype_len_sew(s, type, vece);
> -        tcg_out_opc_vv_vi(s, OPC_VSSUBU_VV, OPC_VSSUBU_VI, a0, a1, a2, c2);
> +        tcg_out_opc_vv_vi(s, OPC_VSSUBU_VV, OPC_VSSUBU_VI, a0, a1,
> +                          c2 ? vec_imm(a2, vece) : a2, c2);
>          break;
>      case INDEX_op_smax_vec:
>          set_vtype_len_sew(s, type, vece);

This is technically correct. That said, the goal of all this extra code 
is to satisfy the assert added in commit 006352d69f14 ("tcg/riscv64: 
Assert immediate in range for {i,s,u,vi}-type insns") not to fix the 
code generation which is correct as it only keeps the lower 5 bits of 
the immediate.

At this stage we already know that the immediate can be represented as a 
duplicated simm5 constant, so just dropping the assert could be a 
simpler way to fix the issue.

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                     http://aurel32.net


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 4/6] tcg/riscv64: Fix constant handling in vector comparisons and selects
  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
  1 sibling, 0 replies; 21+ messages in thread
From: Aurelien Jarno @ 2026-10-29 18:31 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: qemu-devel, qemu-riscv, Daniel Henrique Barboza,
	Richard Henderson, Alistair Francis, Peter Maydell,
	Palmer Dabbelt, qemu-arm

On 2026-10-28 15:33, Philippe Mathieu-Daudé wrote:
> tcg_out_cmpsel() takes constants as TCGReg and passes them to the
> encoders unextracted. In a release build, "cmlt v0.8h, #0" emitted
> the illegal instruction 0xffffb057.
> 
> Use TCGArg for these operands and extract the element with
> vec_imm() before encoding, including before the LT/GE adjustment.
> 
> Fixes: 006352d69f14 ("tcg/riscv64: Assert immediate in range ...")
> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> ---
>  tcg/riscv64/tcg-target.c.inc | 13 +++++++------
>  1 file changed, 7 insertions(+), 6 deletions(-)
> 
> diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
> index a3d995e290b7..168932711796 100644
> --- a/tcg/riscv64/tcg-target.c.inc
> +++ b/tcg/riscv64/tcg-target.c.inc
> @@ -1555,9 +1555,9 @@ static void tcg_out_cltz(TCGContext *s, TCGType type, RISCVInsn insn,
>  
>  static void tcg_out_cmpsel(TCGContext *s, TCGType type, unsigned vece,
>                             TCGCond cond, TCGReg ret,
> -                           TCGReg cmp1, TCGReg cmp2, bool c_cmp2,
> -                           TCGReg val1, bool c_val1,
> -                           TCGReg val2, bool c_val2)
> +                           TCGReg cmp1, TCGArg cmp2, bool c_cmp2,
> +                           TCGArg val1, bool c_val1,
> +                           TCGArg val2, bool c_val2)
>  {
>      set_vtype_len_sew(s, type, vece);
>  
> @@ -1574,7 +1574,7 @@ static void tcg_out_cmpsel(TCGContext *s, TCGType type, unsigned vece,
>      /* Perform the comparison into V0 mask. */
>      if (c_cmp2) {
>          tcg_out_opc_vi(s, tcg_cmpcond_to_rvv_vi[cond].op, TCG_REG_V0, cmp1,
> -                       cmp2 - tcg_cmpcond_to_rvv_vi[cond].adjust);
> +                       vec_imm(cmp2, vece) - tcg_cmpcond_to_rvv_vi[cond].adjust);
>      } else if (tcg_cmpcond_to_rvv_vv[cond].swap) {
>          tcg_out_opc_vv(s, tcg_cmpcond_to_rvv_vv[cond].op,
>                         TCG_REG_V0, cmp2, cmp1);
> @@ -1584,11 +1584,12 @@ static void tcg_out_cmpsel(TCGContext *s, TCGType type, unsigned vece,
>      }
>      if (c_val1) {
>          if (c_val2) {
> -            tcg_out_opc_vi(s, OPC_VMV_V_I, ret, 0, val2);
> +            tcg_out_opc_vi(s, OPC_VMV_V_I, ret, 0, vec_imm(val2, vece));
>              val2 = ret;
>          }
>          /* vd[i] == v0.mask[i] ? imm : vs2[i] */
> -        tcg_out_opc_vim_mask(s, OPC_VMERGE_VIM, ret, val2, val1);
> +        tcg_out_opc_vim_mask(s, OPC_VMERGE_VIM, ret, val2,
> +                             vec_imm(val1, vece));
>      } else {
>          /* vd[i] == v0.mask[i] ? vs1[i] : vs2[i] */
>          tcg_out_opc_vvm_mask(s, OPC_VMERGE_VVM, ret, val2, val1);

Similar to my previous comment. This is technically correct, but if such 
an instruction is generated, it also means that a field is not properly 
masked when generating the opcode.

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                     http://aurel32.net


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 5/6] tcg/riscv64: Fix logical vector immediate matching and emission
  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 18:33   ` Aurelien Jarno
  2026-10-30  8:08     ` Philippe Mathieu-Daudé
  1 sibling, 1 reply; 21+ messages in thread
From: Aurelien Jarno @ 2026-10-29 18:33 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: qemu-devel, qemu-riscv, Daniel Henrique Barboza,
	Richard Henderson, Alistair Francis, Peter Maydell,
	Palmer Dabbelt, qemu-arm, qemu-stable

On 2026-10-28 15:33, Philippe Mathieu-Daudé wrote:
> and/or/xor_vec always have VECE 0, yet their constant was matched
> as a byte element and applied at the stale SEW of the previous op:
> "bic v4.8h, #0xf0" became "vand.vi ..., 15".
> 
> Add the 'N' constraint: use the smallest element size at which the
> constant replicates, if that element fits simm5, and switch SEW to
> it. A wider element can't fit when the smallest doesn't: its upper
> half repeats the smaller element, which would then be 0 or -1.
> 
> Cc: qemu-stable@nongnu.org
> Fixes: 5a63f5998791 ("tcg/riscv: Add support for basic vector opcodes")
> Reported-by: Aurelien Jarno <aurelien@aurel32.net>
> Suggested-by: Richard Henderson <richard.henderson@linaro.org>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> ---
>  tcg/riscv64/tcg-target-con-set.h |  1 +
>  tcg/riscv64/tcg-target-con-str.h |  1 +
>  tcg/riscv64/tcg-target.c.inc     | 53 +++++++++++++++++++++++++++-----
>  3 files changed, 48 insertions(+), 7 deletions(-)
> 
> diff --git a/tcg/riscv64/tcg-target-con-set.h b/tcg/riscv64/tcg-target-con-set.h
> index 0fc26d3f98b4..9b4e219fac16 100644
> --- a/tcg/riscv64/tcg-target-con-set.h
> +++ b/tcg/riscv64/tcg-target-con-set.h
> @@ -26,4 +26,5 @@ C_O1_I2(v, v, v)
>  C_O1_I2(v, vK, v)
>  C_O1_I2(v, v, vK)
>  C_O1_I2(v, v, vL)
> +C_O1_I2(v, v, vN)
>  C_O1_I4(v, v, vL, vK, vK)
> diff --git a/tcg/riscv64/tcg-target-con-str.h b/tcg/riscv64/tcg-target-con-str.h
> index c04e15ddfa3c..d7e8b2ce4f2f 100644
> --- a/tcg/riscv64/tcg-target-con-str.h
> +++ b/tcg/riscv64/tcg-target-con-str.h
> @@ -19,3 +19,4 @@ CONST('I', TCG_CT_CONST_S12)
>  CONST('K', TCG_CT_CONST_S5)
>  CONST('L', TCG_CT_CONST_CMP_VI)
>  CONST('M', TCG_CT_CONST_M12)
> +CONST('N', TCG_CT_CONST_LOGICAL_VI)
> diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
> index 168932711796..4faf7ff36e07 100644
> --- a/tcg/riscv64/tcg-target.c.inc
> +++ b/tcg/riscv64/tcg-target.c.inc
> @@ -116,6 +116,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot)
>  #define TCG_CT_CONST_M12     0x200
>  #define TCG_CT_CONST_S5      0x400
>  #define TCG_CT_CONST_CMP_VI  0x800
> +#define TCG_CT_CONST_LOGICAL_VI 0x1000
>  
>  #define ALL_GENERAL_REGS   MAKE_64BIT_MASK(0, 32)
>  #define ALL_VECTOR_REGS    MAKE_64BIT_MASK(32, 32)
> @@ -384,6 +385,22 @@ static const struct {
>      [TCG_COND_GEU] = { OPC_VMSGTU_VI,   1, 16, true  },
>  };
>  
> +/*
> + * Return the element size at which VAL is a replicated simm5,
> + * or -1 if there is none.  Used for vector logical ops, whose
> + * VECE is not meaningful.
> + */
> +static int vec_logical_immediate_vece(int64_t val)
> +{
> +    for (int e = MO_8; e <= MO_64; e++) {
> +        if (val == dup_const(e, val)) {
> +            int64_t x = sextract64(val, 0, 8 << e);
> +            return x >= -0x10 && x <= 0x0f ? e : -1;
> +        }
> +    }
> +    g_assert_not_reached();
> +}
> +
>  /* test if a constant matches the constraint */
>  static bool tcg_target_const_match(int64_t val, int ct,
>                                     TCGType type, TCGCond cond, int vece)
> @@ -391,6 +408,10 @@ static bool tcg_target_const_match(int64_t val, int ct,
>      if (ct & TCG_CT_CONST) {
>          return 1;
>      }
> +    if ((ct & TCG_CT_CONST_LOGICAL_VI) &&
> +        vec_logical_immediate_vece(val) >= 0) {
> +        return true;
> +    }
>      if (type >= TCG_TYPE_V64) {
>          /* Val is replicated by VECE; extract the highest element. */
>          val >>= (-8 << vece) & 63;
> @@ -2769,6 +2790,23 @@ static const TCGOutOpStore outop_st = {
>  };
>  
>  
> +static void tcg_out_opc_vv_vi_logical(TCGContext *s, TCGType type,
> +                                      RISCVInsn o_vv, RISCVInsn o_vi,
> +                                      TCGReg vd, TCGReg vs2,
> +                                      TCGArg vi1, int c_vi1)
> +{
> +    if (c_vi1) {
> +        int vece = vec_logical_immediate_vece(vi1);
> +
> +        tcg_debug_assert(vece >= 0);
> +        set_vtype_len_sew(s, type, vece);
> +        tcg_out_opc_vi(s, o_vi, vd, vs2, vec_imm(vi1, vece));
> +    } else {
> +        set_vtype_len(s, type);
> +        tcg_out_opc_vv(s, o_vv, vd, vs2, vi1);
> +    }
> +}
> +
>  static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
>                             unsigned vecl, unsigned vece,
>                             const TCGArg args[TCG_MAX_OP_ARGS],
> @@ -2807,16 +2845,16 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
>          }
>          break;
>      case INDEX_op_and_vec:
> -        set_vtype_len(s, type);
> -        tcg_out_opc_vv_vi(s, OPC_VAND_VV, OPC_VAND_VI, a0, a1, a2, c2);
> +        tcg_out_opc_vv_vi_logical(s, type, OPC_VAND_VV, OPC_VAND_VI,
> +                                  a0, a1, a2, c2);
>          break;
>      case INDEX_op_or_vec:
> -        set_vtype_len(s, type);
> -        tcg_out_opc_vv_vi(s, OPC_VOR_VV, OPC_VOR_VI, a0, a1, a2, c2);
> +        tcg_out_opc_vv_vi_logical(s, type, OPC_VOR_VV, OPC_VOR_VI,
> +                                  a0, a1, a2, c2);
>          break;
>      case INDEX_op_xor_vec:
> -        set_vtype_len(s, type);
> -        tcg_out_opc_vv_vi(s, OPC_VXOR_VV, OPC_VXOR_VI, a0, a1, a2, c2);
> +        tcg_out_opc_vv_vi_logical(s, type, OPC_VXOR_VV, OPC_VXOR_VI,
> +                                  a0, a1, a2, c2);
>          break;
>      case INDEX_op_not_vec:
>          set_vtype_len(s, type);
> @@ -3008,10 +3046,11 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags)
>      case INDEX_op_sari_vec:
>      case INDEX_op_rotli_vec:
>          return C_O1_I1(v, v);
> -    case INDEX_op_add_vec:
>      case INDEX_op_and_vec:
>      case INDEX_op_or_vec:
>      case INDEX_op_xor_vec:
> +        return C_O1_I2(v, v, vN);
> +    case INDEX_op_add_vec:
>      case INDEX_op_ssadd_vec:
>      case INDEX_op_sssub_vec:
>      case INDEX_op_usadd_vec:

I am still wondering why not propagating VECE for logical ops at the TCG 
level, instead of recomputing it at the TCG target level. But this is 
how TCG is currently designed, so:

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                     http://aurel32.net


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 3/6] tcg/riscv64: Extract elements for vector arithmetic immediates
  2026-10-29 18:18   ` Aurelien Jarno
@ 2026-10-30  8:05     ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-10-30  8:05 UTC (permalink / raw)
  To: Aurelien Jarno
  Cc: qemu-devel, qemu-riscv, Daniel Henrique Barboza,
	Richard Henderson, Alistair Francis, Peter Maydell,
	Palmer Dabbelt, qemu-arm

On 29/10/26 19:18, Aurelien Jarno wrote:
> On 2026-10-28 15:33, Philippe Mathieu-Daudé wrote:
>> The .vi emitters for add, reverse sub and saturating ops pass the
>> whole replicated constant (e.g. 0x0505050505050505) to encode_vi()
>> instead of a single element. This aborts debug builds on common
>> vectorized guest code and is undefined behaviour in release builds.

I'll reword as:

   The .vi emitters pass the whole replicated constant (e.g.
   0x0505050505050505) instead of one element. The encoding is still
   correct, because encode_vi() keeps the low 5 bits, but it trips the
   range assert added in 006352d69f14 on common vectorized guest code
   in debug builds. Extract the VECE element with vec_imm(), so the
   assert keeps checking that the emitter agrees with the constraint
   matcher.

>>
>> Add vec_imm() to extract the VECE element, and use it.
>>
>> Fixes: 006352d69f14 ("tcg/riscv64: Assert immediate in range ...")
>> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
>> ---
>>   tcg/riscv64/tcg-target.c.inc | 23 +++++++++++++++++------
>>   1 file changed, 17 insertions(+), 6 deletions(-)
>>
>> diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
>> index 0e749ae296b8..a3d995e290b7 100644
>> --- a/tcg/riscv64/tcg-target.c.inc
>> +++ b/tcg/riscv64/tcg-target.c.inc
>> @@ -735,6 +735,12 @@ static void tcg_out_opc_vi_u(TCGContext *s, RISCVInsn opc,
>>       tcg_out32(s, encode_vi_u(opc, vd, imm, vs2, true));
>>   }
>>   
>> +/* Constants are replicated by VECE; extract one element for .vi forms. */
>> +static int64_t vec_imm(TCGArg arg, unsigned vece)
>> +{
>> +    return sextract64(arg, 0, 8 << vece);
>> +}
>> +
>>   static void tcg_out_opc_vv_vi(TCGContext *s, RISCVInsn o_vv, RISCVInsn o_vi,
>>                                 TCGReg vd, TCGReg vs2, TCGArg vi1, int c_vi1)
>>   {
>> @@ -2788,12 +2794,13 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
>>           break;
>>       case INDEX_op_add_vec:
>>           set_vtype_len_sew(s, type, vece);
>> -        tcg_out_opc_vv_vi(s, OPC_VADD_VV, OPC_VADD_VI, a0, a1, a2, c2);
>> +        tcg_out_opc_vv_vi(s, OPC_VADD_VV, OPC_VADD_VI, a0, a1,
>> +                          c2 ? vec_imm(a2, vece) : a2, c2);
>>           break;
>>       case INDEX_op_sub_vec:
>>           set_vtype_len_sew(s, type, vece);
>>           if (const_args[1]) {
>> -            tcg_out_opc_vi(s, OPC_VRSUB_VI, a0, a2, a1);
>> +            tcg_out_opc_vi(s, OPC_VRSUB_VI, a0, a2, vec_imm(a1, vece));
>>           } else {
>>               tcg_out_opc_vv(s, OPC_VSUB_VV, a0, a1, a2);
>>           }
>> @@ -2824,19 +2831,23 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
>>           break;
>>       case INDEX_op_ssadd_vec:
>>           set_vtype_len_sew(s, type, vece);
>> -        tcg_out_opc_vv_vi(s, OPC_VSADD_VV, OPC_VSADD_VI, a0, a1, a2, c2);
>> +        tcg_out_opc_vv_vi(s, OPC_VSADD_VV, OPC_VSADD_VI, a0, a1,
>> +                          c2 ? vec_imm(a2, vece) : a2, c2);
>>           break;
>>       case INDEX_op_sssub_vec:
>>           set_vtype_len_sew(s, type, vece);
>> -        tcg_out_opc_vv_vi(s, OPC_VSSUB_VV, OPC_VSSUB_VI, a0, a1, a2, c2);
>> +        tcg_out_opc_vv_vi(s, OPC_VSSUB_VV, OPC_VSSUB_VI, a0, a1,
>> +                          c2 ? vec_imm(a2, vece) : a2, c2);
>>           break;
>>       case INDEX_op_usadd_vec:
>>           set_vtype_len_sew(s, type, vece);
>> -        tcg_out_opc_vv_vi(s, OPC_VSADDU_VV, OPC_VSADDU_VI, a0, a1, a2, c2);
>> +        tcg_out_opc_vv_vi(s, OPC_VSADDU_VV, OPC_VSADDU_VI, a0, a1,
>> +                          c2 ? vec_imm(a2, vece) : a2, c2);
>>           break;
>>       case INDEX_op_ussub_vec:
>>           set_vtype_len_sew(s, type, vece);
>> -        tcg_out_opc_vv_vi(s, OPC_VSSUBU_VV, OPC_VSSUBU_VI, a0, a1, a2, c2);
>> +        tcg_out_opc_vv_vi(s, OPC_VSSUBU_VV, OPC_VSSUBU_VI, a0, a1,
>> +                          c2 ? vec_imm(a2, vece) : a2, c2);
>>           break;
>>       case INDEX_op_smax_vec:
>>           set_vtype_len_sew(s, type, vece);
> 
> This is technically correct. That said, the goal of all this extra code
> is to satisfy the assert added in commit 006352d69f14 ("tcg/riscv64:
> Assert immediate in range for {i,s,u,vi}-type insns") not to fix the
> code generation which is correct as it only keeps the lower 5 bits of
> the immediate.
> 
> At this stage we already know that the immediate can be represented as a
> duplicated simm5 constant, so just dropping the assert could be a
> simpler way to fix the issue.

IIUC that assert was added on purpose, together with the matching ones 
for imm12, simm12 and uimm20. If we drop the vi assert, the emitter
stops checking that it agrees with the matcher; and vec_imm() costs
only five lines. The reworded description should clarify that.


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 5/6] tcg/riscv64: Fix logical vector immediate matching and emission
  2026-10-29 18:33   ` Aurelien Jarno
@ 2026-10-30  8:08     ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-10-30  8:08 UTC (permalink / raw)
  To: Aurelien Jarno
  Cc: qemu-devel, qemu-riscv, Daniel Henrique Barboza,
	Richard Henderson, Alistair Francis, Peter Maydell,
	Palmer Dabbelt, qemu-arm, qemu-stable

On 29/10/26 19:33, Aurelien Jarno wrote:
> On 2026-10-28 15:33, Philippe Mathieu-Daudé wrote:
>> and/or/xor_vec always have VECE 0, yet their constant was matched
>> as a byte element and applied at the stale SEW of the previous op:
>> "bic v4.8h, #0xf0" became "vand.vi ..., 15".
>>
>> Add the 'N' constraint: use the smallest element size at which the
>> constant replicates, if that element fits simm5, and switch SEW to
>> it. A wider element can't fit when the smallest doesn't: its upper
>> half repeats the smaller element, which would then be 0 or -1.
>>
>> Cc: qemu-stable@nongnu.org
>> Fixes: 5a63f5998791 ("tcg/riscv: Add support for basic vector opcodes")
>> Reported-by: Aurelien Jarno <aurelien@aurel32.net>
>> Suggested-by: Richard Henderson <richard.henderson@linaro.org>
>> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
>> ---
>>   tcg/riscv64/tcg-target-con-set.h |  1 +
>>   tcg/riscv64/tcg-target-con-str.h |  1 +
>>   tcg/riscv64/tcg-target.c.inc     | 53 +++++++++++++++++++++++++++-----
>>   3 files changed, 48 insertions(+), 7 deletions(-)


>> @@ -2807,16 +2845,16 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
>>           }
>>           break;
>>       case INDEX_op_and_vec:
>> -        set_vtype_len(s, type);
>> -        tcg_out_opc_vv_vi(s, OPC_VAND_VV, OPC_VAND_VI, a0, a1, a2, c2);
>> +        tcg_out_opc_vv_vi_logical(s, type, OPC_VAND_VV, OPC_VAND_VI,
>> +                                  a0, a1, a2, c2);
>>           break;
>>       case INDEX_op_or_vec:
>> -        set_vtype_len(s, type);
>> -        tcg_out_opc_vv_vi(s, OPC_VOR_VV, OPC_VOR_VI, a0, a1, a2, c2);
>> +        tcg_out_opc_vv_vi_logical(s, type, OPC_VOR_VV, OPC_VOR_VI,
>> +                                  a0, a1, a2, c2);
>>           break;
>>       case INDEX_op_xor_vec:
>> -        set_vtype_len(s, type);
>> -        tcg_out_opc_vv_vi(s, OPC_VXOR_VV, OPC_VXOR_VI, a0, a1, a2, c2);
>> +        tcg_out_opc_vv_vi_logical(s, type, OPC_VXOR_VV, OPC_VXOR_VI,
>> +                                  a0, a1, a2, c2);
>>           break;
>>       case INDEX_op_not_vec:
>>           set_vtype_len(s, type);
>> @@ -3008,10 +3046,11 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags)
>>       case INDEX_op_sari_vec:
>>       case INDEX_op_rotli_vec:
>>           return C_O1_I1(v, v);
>> -    case INDEX_op_add_vec:
>>       case INDEX_op_and_vec:
>>       case INDEX_op_or_vec:
>>       case INDEX_op_xor_vec:
>> +        return C_O1_I2(v, v, vN);
>> +    case INDEX_op_add_vec:
>>       case INDEX_op_ssadd_vec:
>>       case INDEX_op_sssub_vec:
>>       case INDEX_op_usadd_vec:
> 
> I am still wondering why not propagating VECE for logical ops at the TCG
> level, instead of recomputing it at the TCG target level. But this is
> how TCG is currently designed,

AND/OR/XOR are bitwise, so VECE doesn't matter to the generic layer.
Indeed propagating it would be a separate tcg-op change.

> so:
> 
> Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
> 

Thanks!



^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2026-10-30  8:09 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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-30  8:05     ` Philippe Mathieu-Daudé
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-30  8:08     ` Philippe Mathieu-Daudé
2026-10-28 14:33 ` [PATCH v3 6/6] tests/tcg/aarch64: Add vector immediate regression tests Philippe Mathieu-Daudé
2026-10-29 12:22   ` Richard Henderson

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.