* [PATCH v2 01/18] target/riscv: Add packed SIMD extension state
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
@ 2026-07-17 10:06 ` Molly Chen
2026-07-26 19:32 ` Daniel Henrique Barboza
` (2 more replies)
2026-07-17 10:06 ` [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework Molly Chen
` (18 subsequent siblings)
19 siblings, 3 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:06 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel, Yin Zhang, Dajun Huang,
Zhiyuan Yang
Model vxsat with separate Vector/Zve and P-only control paths. When
Zve* is present, vxsat follows mstatus.VS/vsstatus.VS; when P is
implemented without Zve*, stateen0.VXSAT controls access instead.
Record the P-only stateen result in TB flags so cached translations
preserve both instruction legality and the illegal-vs-virtual exception
class.
Co-authored-by: Yin Zhang <zhangyin2018@iscas.ac.cn>
Co-authored-by: Dajun Huang <djhuang_1@std.uestc.edu.cn>
Co-authored-by: Zhiyuan Yang <zhiyuan.plct@isrc.iscas.ac.cn>
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/cpu.c | 5 ++--
target/riscv/cpu.h | 8 +++++++
target/riscv/cpu_bits.h | 2 ++
target/riscv/machine.c | 19 +++++++++++++++
target/riscv/tcg/csr.c | 39 +++++++++++++++++++++++++++++--
target/riscv/tcg/tcg-cpu.c | 48 ++++++++++++++++++++++++++++++++++++++
6 files changed, 117 insertions(+), 4 deletions(-)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 5a82e6563bf..c9e6c83a491 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -46,7 +46,7 @@
/* RISC-V CPU definitions */
static const char riscv_single_letter_exts[] = "IEMAFDQCBPVH";
const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV,
- RVC, RVS, RVU, RVH, RVG, RVB, 0};
+ RVC, RVS, RVU, RVH, RVG, RVB, RVP, 0};
#define RISCV_CPU_MVENDORID 0
#define RISCV_CPU_MIMPID 0
/*
@@ -1489,7 +1489,8 @@ static const MISAExtInfo misa_ext_info_arr[] = {
MISA_EXT_INFO(RVH, "h", "Hypervisor"),
MISA_EXT_INFO(RVV, "v", "Vector operations"),
MISA_EXT_INFO(RVG, "g", "General purpose (IMAFD_Zicsr_Zifencei)"),
- MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)")
+ MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)"),
+ MISA_EXT_INFO(RVP, "x-p", "Packed-SIMD instructions")
};
static void riscv_cpu_validate_misa_mxl(RISCVCPUClass *mcc)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index c9dfa7daff2..75cfb16d846 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -70,6 +70,7 @@ typedef struct CPUArchState CPURISCVState;
#define RVG RV('G')
#define RVB RV('B')
#define RVX RV('X')
+#define RVP RV('P')
extern const uint32_t misa_bits[];
const char *riscv_get_misa_ext_name(uint32_t bit);
@@ -742,6 +743,13 @@ FIELD(TB_FLAGS, PM_SIGNEXTEND, 31, 1)
FIELD(EXT_TB_FLAGS, MISA_EXT, 0, 32)
FIELD(EXT_TB_FLAGS, ALTFMT, 32, 1)
FIELD(EXT_TB_FLAGS, BIG_ENDIAN, 33, 1)
+FIELD(EXT_TB_FLAGS, P_VXSAT_EXCP, 34, 2)
+
+enum {
+ P_VXSAT_EXCP_NONE,
+ P_VXSAT_EXCP_ILLEGAL,
+ P_VXSAT_EXCP_VIRTUAL,
+};
#ifdef TARGET_RISCV32
#define riscv_cpu_mxl(env) ((void)(env), MXL_RV32)
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 3f146a43fe4..fa7bf60f4fc 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -355,6 +355,8 @@
#define SMSTATEEN0_CS (1ULL << 0)
#define SMSTATEEN0_FCSR (1ULL << 1)
#define SMSTATEEN0_JVT (1ULL << 2)
+/* Packed-SIMD draft: enable access to vxsat when misa.V = 0. */
+#define SMSTATEEN0_VXSAT (1ULL << 3)
#define SMSTATEEN0_CTR (1ULL << 54)
#define SMSTATEEN0_P1P13 (1ULL << 56)
#define SMSTATEEN0_HSCONTXT (1ULL << 57)
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 0ab613a2980..a9cd7e4c1cc 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -158,6 +158,24 @@ static const VMStateDescription vmstate_vector = {
}
};
+static bool p_vxsat_needed(void *opaque)
+{
+ RISCVCPU *cpu = opaque;
+
+ return riscv_has_ext(&cpu->env, RVP) && !cpu->cfg.ext_zve32x;
+}
+
+static const VMStateDescription vmstate_p_vxsat = {
+ .name = "cpu/p-vxsat",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = p_vxsat_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT8(env.vxsat, RISCVCPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static bool pointermasking_needed(void *opaque)
{
return false;
@@ -518,6 +536,7 @@ const VMStateDescription vmstate_riscv_cpu = {
&vmstate_pmp,
&vmstate_hyper,
&vmstate_vector,
+ &vmstate_p_vxsat,
&vmstate_pointermasking,
&vmstate_rv128,
#ifdef CONFIG_KVM
diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c
index 36f2004bc56..e809997f52e 100644
--- a/target/riscv/tcg/csr.c
+++ b/target/riscv/tcg/csr.c
@@ -109,6 +109,24 @@ static RISCVException vs(CPURISCVState *env, int csrno)
return RISCV_EXCP_ILLEGAL_INST;
}
+/* vxsat is also architectural state when P is implemented without Zve*. */
+static RISCVException vxsat(CPURISCVState *env, int csrno)
+{
+ if (riscv_cpu_cfg(env)->ext_zve32x) {
+ return vs(env, csrno);
+ }
+
+ if (riscv_has_ext(env, RVP)) {
+#if !defined(CONFIG_USER_ONLY)
+ return smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
+#else
+ return RISCV_EXCP_NONE;
+#endif
+ }
+
+ return RISCV_EXCP_ILLEGAL_INST;
+}
+
static RISCVException ctr(CPURISCVState *env, int csrno)
{
#if !defined(CONFIG_USER_ONLY)
@@ -1013,7 +1031,12 @@ static RISCVException write_vxsat(CPURISCVState *env, int csrno,
target_ulong val, uintptr_t ra)
{
#if !defined(CONFIG_USER_ONLY)
- env->mstatus |= MSTATUS_VS;
+ if (riscv_cpu_cfg(env)->ext_zve32x) {
+ env->mstatus |= MSTATUS_VS;
+ if (env->virt_enabled) {
+ env->mstatus_hs |= MSTATUS_VS;
+ }
+ }
#endif
env->vxsat = val & BIT(0);
return RISCV_EXCP_NONE;
@@ -3494,6 +3517,10 @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno,
target_ulong new_val, uintptr_t ra)
{
uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
+
+ if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
+ wr_mask |= SMSTATEEN0_VXSAT;
+ }
if (!riscv_has_ext(env, RVF)) {
wr_mask |= SMSTATEEN0_FCSR;
}
@@ -3617,6 +3644,10 @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno,
{
uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
+ if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
+ wr_mask |= SMSTATEEN0_VXSAT;
+ }
+
if (!riscv_has_ext(env, RVF)) {
wr_mask |= SMSTATEEN0_FCSR;
}
@@ -3746,6 +3777,10 @@ static RISCVException write_sstateen0(CPURISCVState *env, int csrno,
{
uint64_t wr_mask = 0;
+ if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
+ wr_mask |= SMSTATEEN0_VXSAT;
+ }
+
if (!riscv_has_ext(env, RVF)) {
wr_mask |= SMSTATEEN0_FCSR;
}
@@ -5916,7 +5951,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_FCSR] = { "fcsr", fs, read_fcsr, write_fcsr },
/* Vector CSRs */
[CSR_VSTART] = { "vstart", vs, read_vstart, write_vstart },
- [CSR_VXSAT] = { "vxsat", vs, read_vxsat, write_vxsat },
+ [CSR_VXSAT] = { "vxsat", vxsat, read_vxsat, write_vxsat },
[CSR_VXRM] = { "vxrm", vs, read_vxrm, write_vxrm },
[CSR_VCSR] = { "vcsr", vs, read_vcsr, write_vcsr },
[CSR_VL] = { "vl", vs, read_vl },
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 4af5cd9c731..1665583accf 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -160,6 +160,8 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
fs = EXT_STATUS_DIRTY;
vs = EXT_STATUS_DIRTY;
#else
+ RISCVException p_vxsat_excp;
+
flags = FIELD_DP32(flags, TB_FLAGS, PRIV, env->priv);
flags |= riscv_env_mmu_index(env, 0);
@@ -182,6 +184,23 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
? EXT_STATUS_DIRTY : EXT_STATUS_DISABLED;
}
+ /*
+ * Without Zve*, all P instructions in the OP-32 and OP-IMM-32
+ * spaces are controlled by stateen0.VXSAT. Preserve the exception
+ * class in the TB flags so translated code can distinguish an illegal
+ * instruction from a virtual-instruction exception.
+ */
+ p_vxsat_excp = smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
+ if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
+ if (p_vxsat_excp == RISCV_EXCP_VIRT_INSTRUCTION_FAULT) {
+ ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
+ P_VXSAT_EXCP_VIRTUAL);
+ } else if (p_vxsat_excp != RISCV_EXCP_NONE) {
+ ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
+ P_VXSAT_EXCP_ILLEGAL);
+ }
+ }
+
if (cpu->cfg.debug && !icount_enabled()) {
flags = FIELD_DP32(flags, TB_FLAGS, ITRIGGER, env->itrigger_enabled);
}
@@ -530,6 +549,28 @@ static void riscv_cpu_validate_b(RISCVCPU *cpu)
}
}
+static void riscv_cpu_validate_p(RISCVCPU *cpu, Error **errp)
+{
+ CPURISCVState *env = &cpu->env;
+
+ if (!riscv_has_ext(env, RVP)) {
+ return;
+ }
+
+ if (riscv_cpu_mxl(env) != MXL_RV32 &&
+ riscv_cpu_mxl(env) != MXL_RV64) {
+ error_setg(errp, "P extension requires RV32 or RV64");
+ return;
+ }
+
+ if (!(cpu->cfg.ext_zmmul && cpu->cfg.ext_zba && cpu->cfg.ext_zbb &&
+ cpu->cfg.ext_zbkb)) {
+ error_setg(errp, "P extension requires zmmul, zba, zbb and zbkb "
+ "extensions");
+ return;
+ }
+}
+
/*
* Check consistency between chosen extensions while setting
* cpu->cfg accordingly.
@@ -612,6 +653,12 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
return;
}
+ riscv_cpu_validate_p(cpu, &local_err);
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
riscv_cpu_validate_v(env, &cpu->cfg, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
@@ -1414,6 +1461,7 @@ static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = {
MISA_CFG(RVV, false),
MISA_CFG(RVG, false),
MISA_CFG(RVB, false),
+ MISA_CFG(RVP, false),
};
/*
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v2 01/18] target/riscv: Add packed SIMD extension state
2026-07-17 10:06 ` [PATCH v2 01/18] target/riscv: Add packed SIMD extension state Molly Chen
@ 2026-07-26 19:32 ` Daniel Henrique Barboza
2026-07-27 6:13 ` Nutty.Liu
2026-07-29 8:43 ` Chao Liu
2 siblings, 0 replies; 31+ messages in thread
From: Daniel Henrique Barboza @ 2026-07-26 19:32 UTC (permalink / raw)
To: Molly Chen, palmer, alistair.francis, liwei1518, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: qemu-riscv, qemu-devel, Yin Zhang, Dajun Huang, Zhiyuan Yang
On 7/17/2026 7:06 AM, Molly Chen wrote:
> Model vxsat with separate Vector/Zve and P-only control paths. When
> Zve* is present, vxsat follows mstatus.VS/vsstatus.VS; when P is
> implemented without Zve*, stateen0.VXSAT controls access instead.
>
> Record the P-only stateen result in TB flags so cached translations
> preserve both instruction legality and the illegal-vs-virtual exception
> class.
>
> Co-authored-by: Yin Zhang <zhangyin2018@iscas.ac.cn>
> Co-authored-by: Dajun Huang <djhuang_1@std.uestc.edu.cn>
> Co-authored-by: Zhiyuan Yang <zhiyuan.plct@isrc.iscas.ac.cn>
>
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
> ---
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> target/riscv/cpu.c | 5 ++--
> target/riscv/cpu.h | 8 +++++++
> target/riscv/cpu_bits.h | 2 ++
> target/riscv/machine.c | 19 +++++++++++++++
> target/riscv/tcg/csr.c | 39 +++++++++++++++++++++++++++++--
> target/riscv/tcg/tcg-cpu.c | 48 ++++++++++++++++++++++++++++++++++++++
> 6 files changed, 117 insertions(+), 4 deletions(-)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 5a82e6563bf..c9e6c83a491 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -46,7 +46,7 @@
> /* RISC-V CPU definitions */
> static const char riscv_single_letter_exts[] = "IEMAFDQCBPVH";
> const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV,
> - RVC, RVS, RVU, RVH, RVG, RVB, 0};
> + RVC, RVS, RVU, RVH, RVG, RVB, RVP, 0};
> #define RISCV_CPU_MVENDORID 0
> #define RISCV_CPU_MIMPID 0
> /*
> @@ -1489,7 +1489,8 @@ static const MISAExtInfo misa_ext_info_arr[] = {
> MISA_EXT_INFO(RVH, "h", "Hypervisor"),
> MISA_EXT_INFO(RVV, "v", "Vector operations"),
> MISA_EXT_INFO(RVG, "g", "General purpose (IMAFD_Zicsr_Zifencei)"),
> - MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)")
> + MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)"),
> + MISA_EXT_INFO(RVP, "x-p", "Packed-SIMD instructions")
> };
>
> static void riscv_cpu_validate_misa_mxl(RISCVCPUClass *mcc)
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index c9dfa7daff2..75cfb16d846 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -70,6 +70,7 @@ typedef struct CPUArchState CPURISCVState;
> #define RVG RV('G')
> #define RVB RV('B')
> #define RVX RV('X')
> +#define RVP RV('P')
>
> extern const uint32_t misa_bits[];
> const char *riscv_get_misa_ext_name(uint32_t bit);
> @@ -742,6 +743,13 @@ FIELD(TB_FLAGS, PM_SIGNEXTEND, 31, 1)
> FIELD(EXT_TB_FLAGS, MISA_EXT, 0, 32)
> FIELD(EXT_TB_FLAGS, ALTFMT, 32, 1)
> FIELD(EXT_TB_FLAGS, BIG_ENDIAN, 33, 1)
> +FIELD(EXT_TB_FLAGS, P_VXSAT_EXCP, 34, 2)
> +
> +enum {
> + P_VXSAT_EXCP_NONE,
> + P_VXSAT_EXCP_ILLEGAL,
> + P_VXSAT_EXCP_VIRTUAL,
> +};
>
> #ifdef TARGET_RISCV32
> #define riscv_cpu_mxl(env) ((void)(env), MXL_RV32)
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 3f146a43fe4..fa7bf60f4fc 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -355,6 +355,8 @@
> #define SMSTATEEN0_CS (1ULL << 0)
> #define SMSTATEEN0_FCSR (1ULL << 1)
> #define SMSTATEEN0_JVT (1ULL << 2)
> +/* Packed-SIMD draft: enable access to vxsat when misa.V = 0. */
> +#define SMSTATEEN0_VXSAT (1ULL << 3)
> #define SMSTATEEN0_CTR (1ULL << 54)
> #define SMSTATEEN0_P1P13 (1ULL << 56)
> #define SMSTATEEN0_HSCONTXT (1ULL << 57)
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index 0ab613a2980..a9cd7e4c1cc 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -158,6 +158,24 @@ static const VMStateDescription vmstate_vector = {
> }
> };
>
> +static bool p_vxsat_needed(void *opaque)
> +{
> + RISCVCPU *cpu = opaque;
> +
> + return riscv_has_ext(&cpu->env, RVP) && !cpu->cfg.ext_zve32x;
> +}
> +
> +static const VMStateDescription vmstate_p_vxsat = {
> + .name = "cpu/p-vxsat",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .needed = p_vxsat_needed,
> + .fields = (const VMStateField[]) {
> + VMSTATE_UINT8(env.vxsat, RISCVCPU),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> static bool pointermasking_needed(void *opaque)
> {
> return false;
> @@ -518,6 +536,7 @@ const VMStateDescription vmstate_riscv_cpu = {
> &vmstate_pmp,
> &vmstate_hyper,
> &vmstate_vector,
> + &vmstate_p_vxsat,
> &vmstate_pointermasking,
> &vmstate_rv128,
> #ifdef CONFIG_KVM
> diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c
> index 36f2004bc56..e809997f52e 100644
> --- a/target/riscv/tcg/csr.c
> +++ b/target/riscv/tcg/csr.c
> @@ -109,6 +109,24 @@ static RISCVException vs(CPURISCVState *env, int csrno)
> return RISCV_EXCP_ILLEGAL_INST;
> }
>
> +/* vxsat is also architectural state when P is implemented without Zve*. */
> +static RISCVException vxsat(CPURISCVState *env, int csrno)
> +{
> + if (riscv_cpu_cfg(env)->ext_zve32x) {
> + return vs(env, csrno);
> + }
> +
> + if (riscv_has_ext(env, RVP)) {
> +#if !defined(CONFIG_USER_ONLY)
> + return smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
> +#else
> + return RISCV_EXCP_NONE;
> +#endif
> + }
> +
> + return RISCV_EXCP_ILLEGAL_INST;
> +}
> +
> static RISCVException ctr(CPURISCVState *env, int csrno)
> {
> #if !defined(CONFIG_USER_ONLY)
> @@ -1013,7 +1031,12 @@ static RISCVException write_vxsat(CPURISCVState *env, int csrno,
> target_ulong val, uintptr_t ra)
> {
> #if !defined(CONFIG_USER_ONLY)
> - env->mstatus |= MSTATUS_VS;
> + if (riscv_cpu_cfg(env)->ext_zve32x) {
> + env->mstatus |= MSTATUS_VS;
> + if (env->virt_enabled) {
> + env->mstatus_hs |= MSTATUS_VS;
> + }
> + }
> #endif
> env->vxsat = val & BIT(0);
> return RISCV_EXCP_NONE;
> @@ -3494,6 +3517,10 @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno,
> target_ulong new_val, uintptr_t ra)
> {
> uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
> +
> + if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> + wr_mask |= SMSTATEEN0_VXSAT;
> + }
> if (!riscv_has_ext(env, RVF)) {
> wr_mask |= SMSTATEEN0_FCSR;
> }
> @@ -3617,6 +3644,10 @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno,
> {
> uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
>
> + if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> + wr_mask |= SMSTATEEN0_VXSAT;
> + }
> +
> if (!riscv_has_ext(env, RVF)) {
> wr_mask |= SMSTATEEN0_FCSR;
> }
> @@ -3746,6 +3777,10 @@ static RISCVException write_sstateen0(CPURISCVState *env, int csrno,
> {
> uint64_t wr_mask = 0;
>
> + if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> + wr_mask |= SMSTATEEN0_VXSAT;
> + }
> +
> if (!riscv_has_ext(env, RVF)) {
> wr_mask |= SMSTATEEN0_FCSR;
> }
> @@ -5916,7 +5951,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> [CSR_FCSR] = { "fcsr", fs, read_fcsr, write_fcsr },
> /* Vector CSRs */
> [CSR_VSTART] = { "vstart", vs, read_vstart, write_vstart },
> - [CSR_VXSAT] = { "vxsat", vs, read_vxsat, write_vxsat },
> + [CSR_VXSAT] = { "vxsat", vxsat, read_vxsat, write_vxsat },
> [CSR_VXRM] = { "vxrm", vs, read_vxrm, write_vxrm },
> [CSR_VCSR] = { "vcsr", vs, read_vcsr, write_vcsr },
> [CSR_VL] = { "vl", vs, read_vl },
> diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
> index 4af5cd9c731..1665583accf 100644
> --- a/target/riscv/tcg/tcg-cpu.c
> +++ b/target/riscv/tcg/tcg-cpu.c
> @@ -160,6 +160,8 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
> fs = EXT_STATUS_DIRTY;
> vs = EXT_STATUS_DIRTY;
> #else
> + RISCVException p_vxsat_excp;
> +
> flags = FIELD_DP32(flags, TB_FLAGS, PRIV, env->priv);
>
> flags |= riscv_env_mmu_index(env, 0);
> @@ -182,6 +184,23 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
> ? EXT_STATUS_DIRTY : EXT_STATUS_DISABLED;
> }
>
> + /*
> + * Without Zve*, all P instructions in the OP-32 and OP-IMM-32
> + * spaces are controlled by stateen0.VXSAT. Preserve the exception
> + * class in the TB flags so translated code can distinguish an illegal
> + * instruction from a virtual-instruction exception.
> + */
> + p_vxsat_excp = smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
> + if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> + if (p_vxsat_excp == RISCV_EXCP_VIRT_INSTRUCTION_FAULT) {
> + ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
> + P_VXSAT_EXCP_VIRTUAL);
> + } else if (p_vxsat_excp != RISCV_EXCP_NONE) {
> + ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
> + P_VXSAT_EXCP_ILLEGAL);
> + }
> + }
> +
> if (cpu->cfg.debug && !icount_enabled()) {
> flags = FIELD_DP32(flags, TB_FLAGS, ITRIGGER, env->itrigger_enabled);
> }
> @@ -530,6 +549,28 @@ static void riscv_cpu_validate_b(RISCVCPU *cpu)
> }
> }
>
> +static void riscv_cpu_validate_p(RISCVCPU *cpu, Error **errp)
> +{
> + CPURISCVState *env = &cpu->env;
> +
> + if (!riscv_has_ext(env, RVP)) {
> + return;
> + }
> +
> + if (riscv_cpu_mxl(env) != MXL_RV32 &&
> + riscv_cpu_mxl(env) != MXL_RV64) {
> + error_setg(errp, "P extension requires RV32 or RV64");
> + return;
> + }
> +
> + if (!(cpu->cfg.ext_zmmul && cpu->cfg.ext_zba && cpu->cfg.ext_zbb &&
> + cpu->cfg.ext_zbkb)) {
> + error_setg(errp, "P extension requires zmmul, zba, zbb and zbkb "
> + "extensions");
> + return;
> + }
> +}
> +
> /*
> * Check consistency between chosen extensions while setting
> * cpu->cfg accordingly.
> @@ -612,6 +653,12 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
> return;
> }
>
> + riscv_cpu_validate_p(cpu, &local_err);
> + if (local_err != NULL) {
> + error_propagate(errp, local_err);
> + return;
> + }
> +
> riscv_cpu_validate_v(env, &cpu->cfg, &local_err);
> if (local_err != NULL) {
> error_propagate(errp, local_err);
> @@ -1414,6 +1461,7 @@ static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = {
> MISA_CFG(RVV, false),
> MISA_CFG(RVG, false),
> MISA_CFG(RVB, false),
> + MISA_CFG(RVP, false),
> };
>
> /*
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v2 01/18] target/riscv: Add packed SIMD extension state
2026-07-17 10:06 ` [PATCH v2 01/18] target/riscv: Add packed SIMD extension state Molly Chen
2026-07-26 19:32 ` Daniel Henrique Barboza
@ 2026-07-27 6:13 ` Nutty.Liu
2026-07-29 8:43 ` Chao Liu
2 siblings, 0 replies; 31+ messages in thread
From: Nutty.Liu @ 2026-07-27 6:13 UTC (permalink / raw)
To: Molly Chen, palmer, alistair.francis, liwei1518, daniel.barboza,
zhiwei_liu, chao.liu.zevorn, Chao Liu
Cc: qemu-riscv, qemu-devel, Yin Zhang, Dajun Huang, Zhiyuan Yang
On 7/17/2026 6:06 PM, Molly Chen wrote:
> Model vxsat with separate Vector/Zve and P-only control paths. When
> Zve* is present, vxsat follows mstatus.VS/vsstatus.VS; when P is
> implemented without Zve*, stateen0.VXSAT controls access instead.
>
> Record the P-only stateen result in TB flags so cached translations
> preserve both instruction legality and the illegal-vs-virtual exception
> class.
>
> Co-authored-by: Yin Zhang <zhangyin2018@iscas.ac.cn>
> Co-authored-by: Dajun Huang <djhuang_1@std.uestc.edu.cn>
> Co-authored-by: Zhiyuan Yang <zhiyuan.plct@isrc.iscas.ac.cn>
>
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Thanks,
Nutty
> ---
> target/riscv/cpu.c | 5 ++--
> target/riscv/cpu.h | 8 +++++++
> target/riscv/cpu_bits.h | 2 ++
> target/riscv/machine.c | 19 +++++++++++++++
> target/riscv/tcg/csr.c | 39 +++++++++++++++++++++++++++++--
> target/riscv/tcg/tcg-cpu.c | 48 ++++++++++++++++++++++++++++++++++++++
> 6 files changed, 117 insertions(+), 4 deletions(-)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 5a82e6563bf..c9e6c83a491 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -46,7 +46,7 @@
> /* RISC-V CPU definitions */
> static const char riscv_single_letter_exts[] = "IEMAFDQCBPVH";
> const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV,
> - RVC, RVS, RVU, RVH, RVG, RVB, 0};
> + RVC, RVS, RVU, RVH, RVG, RVB, RVP, 0};
> #define RISCV_CPU_MVENDORID 0
> #define RISCV_CPU_MIMPID 0
> /*
> @@ -1489,7 +1489,8 @@ static const MISAExtInfo misa_ext_info_arr[] = {
> MISA_EXT_INFO(RVH, "h", "Hypervisor"),
> MISA_EXT_INFO(RVV, "v", "Vector operations"),
> MISA_EXT_INFO(RVG, "g", "General purpose (IMAFD_Zicsr_Zifencei)"),
> - MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)")
> + MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)"),
> + MISA_EXT_INFO(RVP, "x-p", "Packed-SIMD instructions")
> };
>
> static void riscv_cpu_validate_misa_mxl(RISCVCPUClass *mcc)
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index c9dfa7daff2..75cfb16d846 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -70,6 +70,7 @@ typedef struct CPUArchState CPURISCVState;
> #define RVG RV('G')
> #define RVB RV('B')
> #define RVX RV('X')
> +#define RVP RV('P')
>
> extern const uint32_t misa_bits[];
> const char *riscv_get_misa_ext_name(uint32_t bit);
> @@ -742,6 +743,13 @@ FIELD(TB_FLAGS, PM_SIGNEXTEND, 31, 1)
> FIELD(EXT_TB_FLAGS, MISA_EXT, 0, 32)
> FIELD(EXT_TB_FLAGS, ALTFMT, 32, 1)
> FIELD(EXT_TB_FLAGS, BIG_ENDIAN, 33, 1)
> +FIELD(EXT_TB_FLAGS, P_VXSAT_EXCP, 34, 2)
> +
> +enum {
> + P_VXSAT_EXCP_NONE,
> + P_VXSAT_EXCP_ILLEGAL,
> + P_VXSAT_EXCP_VIRTUAL,
> +};
>
> #ifdef TARGET_RISCV32
> #define riscv_cpu_mxl(env) ((void)(env), MXL_RV32)
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 3f146a43fe4..fa7bf60f4fc 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -355,6 +355,8 @@
> #define SMSTATEEN0_CS (1ULL << 0)
> #define SMSTATEEN0_FCSR (1ULL << 1)
> #define SMSTATEEN0_JVT (1ULL << 2)
> +/* Packed-SIMD draft: enable access to vxsat when misa.V = 0. */
> +#define SMSTATEEN0_VXSAT (1ULL << 3)
> #define SMSTATEEN0_CTR (1ULL << 54)
> #define SMSTATEEN0_P1P13 (1ULL << 56)
> #define SMSTATEEN0_HSCONTXT (1ULL << 57)
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index 0ab613a2980..a9cd7e4c1cc 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -158,6 +158,24 @@ static const VMStateDescription vmstate_vector = {
> }
> };
>
> +static bool p_vxsat_needed(void *opaque)
> +{
> + RISCVCPU *cpu = opaque;
> +
> + return riscv_has_ext(&cpu->env, RVP) && !cpu->cfg.ext_zve32x;
> +}
> +
> +static const VMStateDescription vmstate_p_vxsat = {
> + .name = "cpu/p-vxsat",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .needed = p_vxsat_needed,
> + .fields = (const VMStateField[]) {
> + VMSTATE_UINT8(env.vxsat, RISCVCPU),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> static bool pointermasking_needed(void *opaque)
> {
> return false;
> @@ -518,6 +536,7 @@ const VMStateDescription vmstate_riscv_cpu = {
> &vmstate_pmp,
> &vmstate_hyper,
> &vmstate_vector,
> + &vmstate_p_vxsat,
> &vmstate_pointermasking,
> &vmstate_rv128,
> #ifdef CONFIG_KVM
> diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c
> index 36f2004bc56..e809997f52e 100644
> --- a/target/riscv/tcg/csr.c
> +++ b/target/riscv/tcg/csr.c
> @@ -109,6 +109,24 @@ static RISCVException vs(CPURISCVState *env, int csrno)
> return RISCV_EXCP_ILLEGAL_INST;
> }
>
> +/* vxsat is also architectural state when P is implemented without Zve*. */
> +static RISCVException vxsat(CPURISCVState *env, int csrno)
> +{
> + if (riscv_cpu_cfg(env)->ext_zve32x) {
> + return vs(env, csrno);
> + }
> +
> + if (riscv_has_ext(env, RVP)) {
> +#if !defined(CONFIG_USER_ONLY)
> + return smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
> +#else
> + return RISCV_EXCP_NONE;
> +#endif
> + }
> +
> + return RISCV_EXCP_ILLEGAL_INST;
> +}
> +
> static RISCVException ctr(CPURISCVState *env, int csrno)
> {
> #if !defined(CONFIG_USER_ONLY)
> @@ -1013,7 +1031,12 @@ static RISCVException write_vxsat(CPURISCVState *env, int csrno,
> target_ulong val, uintptr_t ra)
> {
> #if !defined(CONFIG_USER_ONLY)
> - env->mstatus |= MSTATUS_VS;
> + if (riscv_cpu_cfg(env)->ext_zve32x) {
> + env->mstatus |= MSTATUS_VS;
> + if (env->virt_enabled) {
> + env->mstatus_hs |= MSTATUS_VS;
> + }
> + }
> #endif
> env->vxsat = val & BIT(0);
> return RISCV_EXCP_NONE;
> @@ -3494,6 +3517,10 @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno,
> target_ulong new_val, uintptr_t ra)
> {
> uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
> +
> + if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> + wr_mask |= SMSTATEEN0_VXSAT;
> + }
> if (!riscv_has_ext(env, RVF)) {
> wr_mask |= SMSTATEEN0_FCSR;
> }
> @@ -3617,6 +3644,10 @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno,
> {
> uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
>
> + if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> + wr_mask |= SMSTATEEN0_VXSAT;
> + }
> +
> if (!riscv_has_ext(env, RVF)) {
> wr_mask |= SMSTATEEN0_FCSR;
> }
> @@ -3746,6 +3777,10 @@ static RISCVException write_sstateen0(CPURISCVState *env, int csrno,
> {
> uint64_t wr_mask = 0;
>
> + if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> + wr_mask |= SMSTATEEN0_VXSAT;
> + }
> +
> if (!riscv_has_ext(env, RVF)) {
> wr_mask |= SMSTATEEN0_FCSR;
> }
> @@ -5916,7 +5951,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> [CSR_FCSR] = { "fcsr", fs, read_fcsr, write_fcsr },
> /* Vector CSRs */
> [CSR_VSTART] = { "vstart", vs, read_vstart, write_vstart },
> - [CSR_VXSAT] = { "vxsat", vs, read_vxsat, write_vxsat },
> + [CSR_VXSAT] = { "vxsat", vxsat, read_vxsat, write_vxsat },
> [CSR_VXRM] = { "vxrm", vs, read_vxrm, write_vxrm },
> [CSR_VCSR] = { "vcsr", vs, read_vcsr, write_vcsr },
> [CSR_VL] = { "vl", vs, read_vl },
> diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
> index 4af5cd9c731..1665583accf 100644
> --- a/target/riscv/tcg/tcg-cpu.c
> +++ b/target/riscv/tcg/tcg-cpu.c
> @@ -160,6 +160,8 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
> fs = EXT_STATUS_DIRTY;
> vs = EXT_STATUS_DIRTY;
> #else
> + RISCVException p_vxsat_excp;
> +
> flags = FIELD_DP32(flags, TB_FLAGS, PRIV, env->priv);
>
> flags |= riscv_env_mmu_index(env, 0);
> @@ -182,6 +184,23 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
> ? EXT_STATUS_DIRTY : EXT_STATUS_DISABLED;
> }
>
> + /*
> + * Without Zve*, all P instructions in the OP-32 and OP-IMM-32
> + * spaces are controlled by stateen0.VXSAT. Preserve the exception
> + * class in the TB flags so translated code can distinguish an illegal
> + * instruction from a virtual-instruction exception.
> + */
> + p_vxsat_excp = smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
> + if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> + if (p_vxsat_excp == RISCV_EXCP_VIRT_INSTRUCTION_FAULT) {
> + ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
> + P_VXSAT_EXCP_VIRTUAL);
> + } else if (p_vxsat_excp != RISCV_EXCP_NONE) {
> + ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
> + P_VXSAT_EXCP_ILLEGAL);
> + }
> + }
> +
> if (cpu->cfg.debug && !icount_enabled()) {
> flags = FIELD_DP32(flags, TB_FLAGS, ITRIGGER, env->itrigger_enabled);
> }
> @@ -530,6 +549,28 @@ static void riscv_cpu_validate_b(RISCVCPU *cpu)
> }
> }
>
> +static void riscv_cpu_validate_p(RISCVCPU *cpu, Error **errp)
> +{
> + CPURISCVState *env = &cpu->env;
> +
> + if (!riscv_has_ext(env, RVP)) {
> + return;
> + }
> +
> + if (riscv_cpu_mxl(env) != MXL_RV32 &&
> + riscv_cpu_mxl(env) != MXL_RV64) {
> + error_setg(errp, "P extension requires RV32 or RV64");
> + return;
> + }
> +
> + if (!(cpu->cfg.ext_zmmul && cpu->cfg.ext_zba && cpu->cfg.ext_zbb &&
> + cpu->cfg.ext_zbkb)) {
> + error_setg(errp, "P extension requires zmmul, zba, zbb and zbkb "
> + "extensions");
> + return;
> + }
> +}
> +
> /*
> * Check consistency between chosen extensions while setting
> * cpu->cfg accordingly.
> @@ -612,6 +653,12 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
> return;
> }
>
> + riscv_cpu_validate_p(cpu, &local_err);
> + if (local_err != NULL) {
> + error_propagate(errp, local_err);
> + return;
> + }
> +
> riscv_cpu_validate_v(env, &cpu->cfg, &local_err);
> if (local_err != NULL) {
> error_propagate(errp, local_err);
> @@ -1414,6 +1461,7 @@ static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = {
> MISA_CFG(RVV, false),
> MISA_CFG(RVG, false),
> MISA_CFG(RVB, false),
> + MISA_CFG(RVP, false),
> };
>
> /*
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v2 01/18] target/riscv: Add packed SIMD extension state
2026-07-17 10:06 ` [PATCH v2 01/18] target/riscv: Add packed SIMD extension state Molly Chen
2026-07-26 19:32 ` Daniel Henrique Barboza
2026-07-27 6:13 ` Nutty.Liu
@ 2026-07-29 8:43 ` Chao Liu
2 siblings, 0 replies; 31+ messages in thread
From: Chao Liu @ 2026-07-29 8:43 UTC (permalink / raw)
To: Molly Chen
Cc: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
Chao Liu, qemu-riscv, qemu-devel, Yin Zhang, Dajun Huang,
Zhiyuan Yang
On Fri, Jul 17, 2026 at 10:06:54AM +0800, Molly Chen wrote:
> Model vxsat with separate Vector/Zve and P-only control paths. When
> Zve* is present, vxsat follows mstatus.VS/vsstatus.VS; when P is
> implemented without Zve*, stateen0.VXSAT controls access instead.
>
> Record the P-only stateen result in TB flags so cached translations
> preserve both instruction legality and the illegal-vs-virtual exception
> class.
>
> Co-authored-by: Yin Zhang <zhangyin2018@iscas.ac.cn>
> Co-authored-by: Dajun Huang <djhuang_1@std.uestc.edu.cn>
> Co-authored-by: Zhiyuan Yang <zhiyuan.plct@isrc.iscas.ac.cn>
>
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> target/riscv/cpu.c | 5 ++--
> target/riscv/cpu.h | 8 +++++++
> target/riscv/cpu_bits.h | 2 ++
> target/riscv/machine.c | 19 +++++++++++++++
> target/riscv/tcg/csr.c | 39 +++++++++++++++++++++++++++++--
> target/riscv/tcg/tcg-cpu.c | 48 ++++++++++++++++++++++++++++++++++++++
> 6 files changed, 117 insertions(+), 4 deletions(-)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 5a82e6563bf..c9e6c83a491 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -46,7 +46,7 @@
> /* RISC-V CPU definitions */
> static const char riscv_single_letter_exts[] = "IEMAFDQCBPVH";
> const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV,
> - RVC, RVS, RVU, RVH, RVG, RVB, 0};
> + RVC, RVS, RVU, RVH, RVG, RVB, RVP, 0};
> #define RISCV_CPU_MVENDORID 0
> #define RISCV_CPU_MIMPID 0
> /*
> @@ -1489,7 +1489,8 @@ static const MISAExtInfo misa_ext_info_arr[] = {
> MISA_EXT_INFO(RVH, "h", "Hypervisor"),
> MISA_EXT_INFO(RVV, "v", "Vector operations"),
> MISA_EXT_INFO(RVG, "g", "General purpose (IMAFD_Zicsr_Zifencei)"),
> - MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)")
> + MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)"),
> + MISA_EXT_INFO(RVP, "x-p", "Packed-SIMD instructions")
> };
>
> static void riscv_cpu_validate_misa_mxl(RISCVCPUClass *mcc)
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index c9dfa7daff2..75cfb16d846 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -70,6 +70,7 @@ typedef struct CPUArchState CPURISCVState;
> #define RVG RV('G')
> #define RVB RV('B')
> #define RVX RV('X')
> +#define RVP RV('P')
>
> extern const uint32_t misa_bits[];
> const char *riscv_get_misa_ext_name(uint32_t bit);
> @@ -742,6 +743,13 @@ FIELD(TB_FLAGS, PM_SIGNEXTEND, 31, 1)
> FIELD(EXT_TB_FLAGS, MISA_EXT, 0, 32)
> FIELD(EXT_TB_FLAGS, ALTFMT, 32, 1)
> FIELD(EXT_TB_FLAGS, BIG_ENDIAN, 33, 1)
> +FIELD(EXT_TB_FLAGS, P_VXSAT_EXCP, 34, 2)
> +
> +enum {
> + P_VXSAT_EXCP_NONE,
> + P_VXSAT_EXCP_ILLEGAL,
> + P_VXSAT_EXCP_VIRTUAL,
> +};
>
> #ifdef TARGET_RISCV32
> #define riscv_cpu_mxl(env) ((void)(env), MXL_RV32)
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 3f146a43fe4..fa7bf60f4fc 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -355,6 +355,8 @@
> #define SMSTATEEN0_CS (1ULL << 0)
> #define SMSTATEEN0_FCSR (1ULL << 1)
> #define SMSTATEEN0_JVT (1ULL << 2)
> +/* Packed-SIMD draft: enable access to vxsat when misa.V = 0. */
> +#define SMSTATEEN0_VXSAT (1ULL << 3)
> #define SMSTATEEN0_CTR (1ULL << 54)
> #define SMSTATEEN0_P1P13 (1ULL << 56)
> #define SMSTATEEN0_HSCONTXT (1ULL << 57)
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index 0ab613a2980..a9cd7e4c1cc 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -158,6 +158,24 @@ static const VMStateDescription vmstate_vector = {
> }
> };
>
> +static bool p_vxsat_needed(void *opaque)
> +{
> + RISCVCPU *cpu = opaque;
> +
> + return riscv_has_ext(&cpu->env, RVP) && !cpu->cfg.ext_zve32x;
> +}
> +
> +static const VMStateDescription vmstate_p_vxsat = {
> + .name = "cpu/p-vxsat",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .needed = p_vxsat_needed,
> + .fields = (const VMStateField[]) {
> + VMSTATE_UINT8(env.vxsat, RISCVCPU),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> static bool pointermasking_needed(void *opaque)
> {
> return false;
> @@ -518,6 +536,7 @@ const VMStateDescription vmstate_riscv_cpu = {
> &vmstate_pmp,
> &vmstate_hyper,
> &vmstate_vector,
> + &vmstate_p_vxsat,
> &vmstate_pointermasking,
> &vmstate_rv128,
> #ifdef CONFIG_KVM
> diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c
> index 36f2004bc56..e809997f52e 100644
> --- a/target/riscv/tcg/csr.c
> +++ b/target/riscv/tcg/csr.c
> @@ -109,6 +109,24 @@ static RISCVException vs(CPURISCVState *env, int csrno)
> return RISCV_EXCP_ILLEGAL_INST;
> }
>
> +/* vxsat is also architectural state when P is implemented without Zve*. */
> +static RISCVException vxsat(CPURISCVState *env, int csrno)
> +{
> + if (riscv_cpu_cfg(env)->ext_zve32x) {
> + return vs(env, csrno);
> + }
> +
> + if (riscv_has_ext(env, RVP)) {
> +#if !defined(CONFIG_USER_ONLY)
> + return smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
> +#else
> + return RISCV_EXCP_NONE;
> +#endif
> + }
> +
> + return RISCV_EXCP_ILLEGAL_INST;
> +}
> +
> static RISCVException ctr(CPURISCVState *env, int csrno)
> {
> #if !defined(CONFIG_USER_ONLY)
> @@ -1013,7 +1031,12 @@ static RISCVException write_vxsat(CPURISCVState *env, int csrno,
> target_ulong val, uintptr_t ra)
> {
> #if !defined(CONFIG_USER_ONLY)
> - env->mstatus |= MSTATUS_VS;
> + if (riscv_cpu_cfg(env)->ext_zve32x) {
> + env->mstatus |= MSTATUS_VS;
> + if (env->virt_enabled) {
> + env->mstatus_hs |= MSTATUS_VS;
> + }
> + }
> #endif
> env->vxsat = val & BIT(0);
> return RISCV_EXCP_NONE;
> @@ -3494,6 +3517,10 @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno,
> target_ulong new_val, uintptr_t ra)
> {
> uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
> +
> + if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> + wr_mask |= SMSTATEEN0_VXSAT;
> + }
> if (!riscv_has_ext(env, RVF)) {
> wr_mask |= SMSTATEEN0_FCSR;
> }
> @@ -3617,6 +3644,10 @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno,
> {
> uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
>
> + if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> + wr_mask |= SMSTATEEN0_VXSAT;
> + }
> +
> if (!riscv_has_ext(env, RVF)) {
> wr_mask |= SMSTATEEN0_FCSR;
> }
> @@ -3746,6 +3777,10 @@ static RISCVException write_sstateen0(CPURISCVState *env, int csrno,
> {
> uint64_t wr_mask = 0;
>
> + if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> + wr_mask |= SMSTATEEN0_VXSAT;
> + }
> +
> if (!riscv_has_ext(env, RVF)) {
> wr_mask |= SMSTATEEN0_FCSR;
> }
> @@ -5916,7 +5951,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> [CSR_FCSR] = { "fcsr", fs, read_fcsr, write_fcsr },
> /* Vector CSRs */
> [CSR_VSTART] = { "vstart", vs, read_vstart, write_vstart },
> - [CSR_VXSAT] = { "vxsat", vs, read_vxsat, write_vxsat },
> + [CSR_VXSAT] = { "vxsat", vxsat, read_vxsat, write_vxsat },
> [CSR_VXRM] = { "vxrm", vs, read_vxrm, write_vxrm },
> [CSR_VCSR] = { "vcsr", vs, read_vcsr, write_vcsr },
> [CSR_VL] = { "vl", vs, read_vl },
> diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
> index 4af5cd9c731..1665583accf 100644
> --- a/target/riscv/tcg/tcg-cpu.c
> +++ b/target/riscv/tcg/tcg-cpu.c
> @@ -160,6 +160,8 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
> fs = EXT_STATUS_DIRTY;
> vs = EXT_STATUS_DIRTY;
> #else
> + RISCVException p_vxsat_excp;
> +
> flags = FIELD_DP32(flags, TB_FLAGS, PRIV, env->priv);
>
> flags |= riscv_env_mmu_index(env, 0);
> @@ -182,6 +184,23 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
> ? EXT_STATUS_DIRTY : EXT_STATUS_DISABLED;
> }
>
> + /*
> + * Without Zve*, all P instructions in the OP-32 and OP-IMM-32
> + * spaces are controlled by stateen0.VXSAT. Preserve the exception
> + * class in the TB flags so translated code can distinguish an illegal
> + * instruction from a virtual-instruction exception.
> + */
> + p_vxsat_excp = smstateen_acc_ok(env, 0, SMSTATEEN0_VXSAT);
> + if (riscv_has_ext(env, RVP) && !riscv_cpu_cfg(env)->ext_zve32x) {
> + if (p_vxsat_excp == RISCV_EXCP_VIRT_INSTRUCTION_FAULT) {
> + ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
> + P_VXSAT_EXCP_VIRTUAL);
> + } else if (p_vxsat_excp != RISCV_EXCP_NONE) {
> + ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, P_VXSAT_EXCP,
> + P_VXSAT_EXCP_ILLEGAL);
> + }
> + }
> +
> if (cpu->cfg.debug && !icount_enabled()) {
> flags = FIELD_DP32(flags, TB_FLAGS, ITRIGGER, env->itrigger_enabled);
> }
> @@ -530,6 +549,28 @@ static void riscv_cpu_validate_b(RISCVCPU *cpu)
> }
> }
>
> +static void riscv_cpu_validate_p(RISCVCPU *cpu, Error **errp)
> +{
> + CPURISCVState *env = &cpu->env;
> +
> + if (!riscv_has_ext(env, RVP)) {
> + return;
> + }
> +
> + if (riscv_cpu_mxl(env) != MXL_RV32 &&
> + riscv_cpu_mxl(env) != MXL_RV64) {
> + error_setg(errp, "P extension requires RV32 or RV64");
> + return;
> + }
> +
> + if (!(cpu->cfg.ext_zmmul && cpu->cfg.ext_zba && cpu->cfg.ext_zbb &&
> + cpu->cfg.ext_zbkb)) {
> + error_setg(errp, "P extension requires zmmul, zba, zbb and zbkb "
> + "extensions");
> + return;
> + }
> +}
> +
> /*
> * Check consistency between chosen extensions while setting
> * cpu->cfg accordingly.
> @@ -612,6 +653,12 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
> return;
> }
>
> + riscv_cpu_validate_p(cpu, &local_err);
> + if (local_err != NULL) {
> + error_propagate(errp, local_err);
> + return;
> + }
> +
> riscv_cpu_validate_v(env, &cpu->cfg, &local_err);
> if (local_err != NULL) {
> error_propagate(errp, local_err);
> @@ -1414,6 +1461,7 @@ static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = {
> MISA_CFG(RVV, false),
> MISA_CFG(RVG, false),
> MISA_CFG(RVB, false),
> + MISA_CFG(RVP, false),
> };
>
> /*
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
2026-07-17 10:06 ` [PATCH v2 01/18] target/riscv: Add packed SIMD extension state Molly Chen
@ 2026-07-17 10:06 ` Molly Chen
2026-07-26 19:53 ` Daniel Henrique Barboza
` (2 more replies)
2026-07-17 10:06 ` [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions Molly Chen
` (17 subsequent siblings)
19 siblings, 3 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:06 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/tcg/meson.build | 3 +-
target/riscv/tcg/psimd_helper.c | 1656 +++++++++++++++++++++++++++++++
2 files changed, 1658 insertions(+), 1 deletion(-)
create mode 100644 target/riscv/tcg/psimd_helper.c
diff --git a/target/riscv/tcg/meson.build b/target/riscv/tcg/meson.build
index a05ab642f41..cc438d7c0d2 100644
--- a/target/riscv/tcg/meson.build
+++ b/target/riscv/tcg/meson.build
@@ -15,7 +15,8 @@ riscv_ss.add(files(
'vcrypto_helper.c',
'vector_helper.c',
'vector_internals.c',
- 'zce_helper.c'))
+ 'zce_helper.c',
+ 'psimd_helper.c'))
riscv_system_ss.add(files(
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
new file mode 100644
index 00000000000..2948bbb2a86
--- /dev/null
+++ b/target/riscv/tcg/psimd_helper.c
@@ -0,0 +1,1656 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* RISC-V Packed SIMD Extension Helpers for QEMU. */
+/* Copyright (C) 2026 ISRC ISCAS. */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
+#include "fpu/softfloat.h"
+#include "internals.h"
+
+
+/* Helper macros */
+
+/* Element count calculations */
+#define ELEMS_B(target) (sizeof(target) * 8 / 8) /* byte elements count */
+#define ELEMS_H(target) (sizeof(target) * 8 / 16)
+#define ELEMS_W(target) (sizeof(target) * 8 / 32) /* word elements count */
+#define ELEMS_D(target) (sizeof(target) * 8 / 64)
+
+/* Element extraction macros - unsigned to avoid sign extension */
+#define EXTRACT8(val, idx) (((val) >> ((idx) * 8)) & 0xFF)
+#define EXTRACT16(val, idx) (((val) >> ((idx) * 16)) & 0xFFFF)
+#define EXTRACT32(val, idx) (((val) >> ((idx) * 32)) & 0xFFFFFFFF)
+#define EXTRACT64(val, idx) (((val) >> ((idx) * 64)) & 0xFFFFFFFFFFFFFFFFULL)
+
+/* Element insertion macros */
+#define INSERT8(val, res, idx) \
+ ((val) | ((target_ulong)(uint8_t)(res) << ((idx) * 8)))
+#define INSERT16(val, res, idx) \
+ ((val) | ((target_ulong)(uint16_t)(res) << ((idx) * 16)))
+#define INSERT32(val, res, idx) \
+ ((val) | ((target_ulong)(uint32_t)(res) << ((idx) * 32)))
+#define INSERT32_64(val, res, idx) \
+ ((val) | ((uint64_t)(uint32_t)(res) << ((idx) * 32)))
+#define INSERT64(val, res, idx) \
+ ((val) | ((uint64_t)(res) << ((idx) * 64)))
+
+/* Saturation constants */
+static const int8_t SAT_MAX_B = 127;
+static const int8_t SAT_MIN_B = -128;
+static const int16_t SAT_MAX_H = 32767;
+static const int16_t SAT_MIN_H = -32768;
+static const int32_t SAT_MAX_W = 2147483647;
+static const int32_t SAT_MIN_W = -2147483648LL;
+static const uint8_t USAT_MAX_B = 255;
+static const uint16_t USAT_MAX_H = 65535;
+static const uint32_t USAT_MAX_W = 4294967295U;
+
+
+/* Saturation helper functions */
+
+/**
+ * Signed saturation for 8-bit elements
+ * Returns saturated value and sets *sat if saturation occurred
+ */
+static inline int8_t signed_saturate_b(int32_t val, int *sat)
+{
+ if (val > SAT_MAX_B) {
+ *sat = 1;
+ return SAT_MAX_B;
+ }
+ if (val < SAT_MIN_B) {
+ *sat = 1;
+ return SAT_MIN_B;
+ }
+ return (int8_t)val;
+}
+
+/**
+ * Signed saturation for 16-bit elements
+ */
+static inline int16_t signed_saturate_h(int32_t val, int *sat)
+{
+ if (val > SAT_MAX_H) {
+ *sat = 1;
+ return SAT_MAX_H;
+ }
+ if (val < SAT_MIN_H) {
+ *sat = 1;
+ return SAT_MIN_H;
+ }
+ return (int16_t)val;
+}
+
+/**
+ * Signed saturation for 32-bit elements
+ */
+static inline int32_t signed_saturate_w(int64_t val, int *sat)
+{
+ if (val > SAT_MAX_W) {
+ *sat = 1;
+ return SAT_MAX_W;
+ }
+ if (val < SAT_MIN_W) {
+ *sat = 1;
+ return SAT_MIN_W;
+ }
+ return (int32_t)val;
+}
+
+/**
+ * Unsigned saturation for 8-bit elements
+ */
+static inline uint8_t unsigned_saturate_b(uint32_t val, int *sat)
+{
+ if (val > USAT_MAX_B) {
+ *sat = 1;
+ return USAT_MAX_B;
+ }
+ return (uint8_t)val;
+}
+
+/**
+ * Unsigned saturation for 16-bit elements
+ */
+static inline uint16_t unsigned_saturate_h(uint32_t val, int *sat)
+{
+ if (val > USAT_MAX_H) {
+ *sat = 1;
+ return USAT_MAX_H;
+ }
+ return (uint16_t)val;
+}
+
+/**
+ * Unsigned saturation for 32-bit elements
+ */
+static inline uint32_t unsigned_saturate_w(uint64_t val, int *sat)
+{
+ if (val > USAT_MAX_W) {
+ *sat = 1;
+ return USAT_MAX_W;
+ }
+ return (uint32_t)val;
+}
+
+static inline target_ulong psimd_abdsumu_b(target_ulong rs1,
+ target_ulong rs2,
+ target_ulong sum)
+{
+ int elems = ELEMS_B(rs1);
+
+ for (int i = 0; i < elems; i++) {
+ uint8_t e1 = EXTRACT8(rs1, i);
+ uint8_t e2 = EXTRACT8(rs2, i);
+ uint8_t diff = (e1 > e2) ? (e1 - e2) : (e2 - e1);
+ sum += diff;
+ }
+
+ return sum;
+}
+
+#define PSIMD_DO_ADD(N, M) ((N) + (M))
+#define PSIMD_DO_SUB(N, M) ((N) - (M))
+#define PSIMD_DO_ABD(N, M) ((N) >= (M) ? (N) - (M) : (M) - (N))
+#define PSIMD_DO_EQ_MASK(N, M) ((N) == (M) ? -1 : 0)
+#define PSIMD_DO_LT_MASK(N, M) ((N) < (M) ? -1 : 0)
+#define PSIMD_DO_MIN(N, M) ((N) < (M) ? (N) : (M))
+#define PSIMD_DO_MAX(N, M) ((N) > (M) ? (N) : (M))
+#define PSIMD_DO_SLL(N, M) ((N) << (M))
+#define PSIMD_DO_SRL(N, M) ((N) >> (M))
+#define PSIMD_DO_SRA(N, M) ((N) >> (M))
+
+#define GEN_PSIMD_BINOP(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT, \
+ ELEMS, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ STYPE e1 = (STYPE)EXTRACT(rs1, i); \
+ STYPE e2 = (STYPE)EXTRACT(rs2, i); \
+ DTYPE res = (DTYPE)OP(e1, e2); \
+ rd = INSERT(rd, res, i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_BINOP_SCALAR(NAME, RTYPE, ETYPE, EXTRACT, INSERT, \
+ ELEMS, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ ETYPE e2 = (ETYPE)EXTRACT(rs2, 0); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE res = OP(e1, e2); \
+ rd = INSERT(rd, res, i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_SHIFTOP(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT, \
+ ELEMS, SHMASK, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ uint8_t shamt = rs2 & (SHMASK); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ STYPE e1 = (STYPE)EXTRACT(rs1, i); \
+ DTYPE res = (DTYPE)OP(e1, shamt); \
+ rd = INSERT(rd, res, i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_SAT_SHIFTOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
+ ELEMS, SHMASK, SAT_FN) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ int sat = 0; \
+ uint8_t shamt = rs2 & (SHMASK); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ WTYPE shifted = (WTYPE)e1 << shamt; \
+ ETYPE res = SAT_FN(shifted, &sat); \
+ rd = INSERT(rd, res, i); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_ROUND_SRAI(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
+ ELEMS, SHMASK) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ uint8_t shamt = rs2 & (SHMASK); \
+ \
+ if (shamt == 0) { \
+ return rs1; \
+ } \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ WTYPE rounded = (((WTYPE)e1 >> (shamt - 1)) + 1) >> 1; \
+ rd = INSERT(rd, (ETYPE)rounded, i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_SAT_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
+ ELEMS, OP, SAT_FN) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ int sat = 0; \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE e2 = (ETYPE)EXTRACT(rs2, i); \
+ WTYPE val = OP((WTYPE)e1, (WTYPE)e2); \
+ ETYPE res = SAT_FN(val, &sat); \
+ rd = INSERT(rd, res, i); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_USUB_SAT(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ int sat = 0; \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE e2 = (ETYPE)EXTRACT(rs2, i); \
+ ETYPE res = (e1 >= e2) ? (e1 - e2) : 0; \
+ if (e1 < e2) { \
+ sat = 1; \
+ } \
+ rd = INSERT(rd, res, i); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_AVG_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
+ ELEMS, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ WTYPE e1 = (WTYPE)(ETYPE)EXTRACT(rs1, i); \
+ WTYPE e2 = (WTYPE)(ETYPE)EXTRACT(rs2, i); \
+ ETYPE res = (ETYPE)(OP(e1, e2) >> 1); \
+ rd = INSERT(rd, res, i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_SHADD(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS, \
+ SHAMT) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE e2 = (ETYPE)EXTRACT(rs2, i); \
+ ETYPE res = (e1 << (SHAMT)) + e2; \
+ rd = INSERT(rd, res, i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_SAT_SHADD(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
+ ELEMS, SHAMT, SH_MIN, SH_MAX, SAT_MIN, \
+ SAT_MAX, SAT_FN) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ int sat = 0; \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE e2 = (ETYPE)EXTRACT(rs2, i); \
+ WTYPE shifted; \
+ \
+ if (e1 > (SH_MAX) || e1 < (SH_MIN)) { \
+ shifted = (e1 < 0) ? (SAT_MIN) : (SAT_MAX); \
+ sat = 1; \
+ } else { \
+ shifted = (WTYPE)e1 << (SHAMT); \
+ } \
+ \
+ WTYPE sum = shifted + e2; \
+ ETYPE res = SAT_FN(sum, &sat); \
+ rd = INSERT(rd, res, i); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_SATI(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
+ ELEMS, IMMMASK) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE imm) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ int range = (imm & (IMMMASK)) + 1; \
+ WTYPE max = ((WTYPE)1 << (range - 1)) - 1; \
+ WTYPE min = -((WTYPE)1 << (range - 1)); \
+ int sat = 0; \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE res; \
+ \
+ if (e1 > max) { \
+ res = max; \
+ sat = 1; \
+ } else if (e1 < min) { \
+ res = min; \
+ sat = 1; \
+ } else { \
+ res = e1; \
+ } \
+ \
+ rd = INSERT(rd, res, i); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_USATI(NAME, RTYPE, ETYPE, UTYPE, WTYPE, EXTRACT, \
+ INSERT, ELEMS, ONE) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE imm) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ WTYPE max = ((WTYPE)(ONE) << imm) - 1; \
+ int sat = 0; \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE res; \
+ \
+ if (e1 < 0) { \
+ res = 0; \
+ sat = 1; \
+ } else if ((UTYPE)e1 > max) { \
+ res = max; \
+ sat = 1; \
+ } else { \
+ res = e1; \
+ } \
+ \
+ rd = INSERT(rd, res, i); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_ABS(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS, \
+ MINVAL, MAXVAL) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ int sat = 0; \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE res; \
+ \
+ if (e1 == (MINVAL)) { \
+ res = (MAXVAL); \
+ sat = 1; \
+ } else if (e1 < 0) { \
+ res = -e1; \
+ } else { \
+ res = e1; \
+ } \
+ \
+ rd = INSERT(rd, res, i); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_SCALAR_ABS(NAME, RTYPE, STYPE, UTYPE) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1) \
+{ \
+ STYPE value = (STYPE)rs1; \
+ UTYPE result = (UTYPE)value; \
+ \
+ if (value < 0) { \
+ result = (UTYPE)0 - result; \
+ } \
+ return (RTYPE)(STYPE)result; \
+}
+
+#define GEN_PSIMD_VAR_SSHA(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
+ ELEMS, BITS, SAT_FN) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ int sat = 0; \
+ int8_t shamt = (int8_t)(rs2 & 0xff); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE res; \
+ \
+ if (shamt >= 0) { \
+ WTYPE shifted = (WTYPE)e1 << shamt; \
+ res = SAT_FN(shifted, &sat); \
+ } else { \
+ int right = -shamt; \
+ if (right >= (BITS)) { \
+ res = (e1 < 0) ? -1 : 0; \
+ } else { \
+ res = e1 >> right; \
+ } \
+ } \
+ \
+ rd = INSERT(rd, res, i); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_VAR_SSHAR(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
+ ELEMS, BITS, SAT_MIN, SAT_MAX, SAT_FN) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ int sat = 0; \
+ int8_t shamt = (int8_t)(rs2 & 0xff); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE res; \
+ \
+ if (shamt >= 0) { \
+ if (shamt >= (BITS)) { \
+ if (e1 == 0) { \
+ res = 0; \
+ } else if (e1 > 0) { \
+ res = (SAT_MAX); \
+ sat = 1; \
+ } else { \
+ res = (SAT_MIN); \
+ sat = 1; \
+ } \
+ } else { \
+ WTYPE shifted = (WTYPE)e1 * ((WTYPE)1 << shamt); \
+ res = SAT_FN(shifted, &sat); \
+ } \
+ } else { \
+ int right = -shamt; \
+ if (right >= (BITS)) { \
+ res = 0; \
+ } else { \
+ WTYPE rounded = ((e1 >> (right - 1)) + 1) >> 1; \
+ res = (ETYPE)rounded; \
+ } \
+ } \
+ \
+ rd = INSERT(rd, res, i); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_VAR_USHL(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
+ ELEMS, BITS, SAT_FN) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ int sat = 0; \
+ int8_t shamt = (int8_t)(rs2 & 0xff); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE res; \
+ \
+ if (shamt >= 0) { \
+ WTYPE shifted = (shamt >= (BITS)) ? \
+ ((WTYPE)e1 << (BITS)) : \
+ ((WTYPE)e1 << shamt); \
+ res = SAT_FN(shifted, &sat); \
+ } else { \
+ int right = -shamt; \
+ if (right >= (BITS)) { \
+ res = 0; \
+ } else { \
+ res = e1 >> right; \
+ } \
+ } \
+ \
+ rd = INSERT(rd, res, i); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_VAR_USHLR(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
+ ELEMS, BITS, SAT_FN) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ int sat = 0; \
+ int8_t shamt = (int8_t)(rs2 & 0xff); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE res; \
+ \
+ if (shamt >= 0) { \
+ WTYPE shifted = (shamt >= (BITS)) ? \
+ ((WTYPE)e1 << (BITS)) : \
+ ((WTYPE)e1 << shamt); \
+ res = SAT_FN(shifted, &sat); \
+ } else { \
+ int right = -shamt; \
+ if (right > (BITS)) { \
+ res = 0; \
+ } else { \
+ WTYPE rounded = ((WTYPE)e1 >> (right - 1)) + 1; \
+ res = (ETYPE)(rounded >> 1); \
+ } \
+ } \
+ \
+ rd = INSERT(rd, res, i); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define PSIMD_DO_SRA64(A, B) ((A) >> (B))
+#define PSIMD_DO_RNDSRA64(A, B) \
+ ((int64_t)((((__int128_t)(A) >> ((B) - 1)) + 1) >> 1))
+
+#define GEN_PSIMD_VAR_SRA64(NAME, RIGHT_OP) \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
+{ \
+ int64_t a = (int64_t)rs1; \
+ int8_t shamt = (int8_t)(rs2 & 0xff); \
+ \
+ if (shamt >= 0) { \
+ return (uint64_t)(a << shamt); \
+ } \
+ \
+ int right = -shamt; \
+ if (right >= 64) { \
+ return (a < 0) ? (uint64_t)-1 : 0; \
+ } \
+ return (uint64_t)RIGHT_OP(a, right); \
+}
+
+#define PSIMD_DO_SRL64(A, B) (((B) >= 64) ? 0 : ((A) >> (B)))
+#define PSIMD_DO_RNDSRL64(A, B) \
+ (((B) > 64) ? 0 : ((((A) >> ((B) - 1)) + 1) >> 1))
+
+#define GEN_PSIMD_VAR_SRL64(NAME, RIGHT_OP) \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
+{ \
+ int8_t shamt = (int8_t)(rs2 & 0xff); \
+ \
+ if (shamt < 0) { \
+ return RIGHT_OP(rs1, -shamt); \
+ } \
+ return (shamt >= 64) ? 0 : (rs1 << shamt); \
+}
+
+#define GEN_PSIMD_XPAIR_BINOP(NAME, RTYPE, ETYPE, EXTRACT, INSERT, \
+ ELEMS, OP_LO, OP_HI) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i += 2) { \
+ ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1); \
+ ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i); \
+ ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1); \
+ ETYPE res_lo = OP_LO(s1_lo, s2_hi); \
+ ETYPE res_hi = OP_HI(s1_hi, s2_lo); \
+ rd = INSERT(rd, res_lo, i); \
+ rd = INSERT(rd, res_hi, i + 1); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_XPAIR_SAT_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, \
+ INSERT, ELEMS, OP_LO, OP_HI, SAT_FN) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ int sat = 0; \
+ \
+ for (int i = 0; i < elems; i += 2) { \
+ ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1); \
+ ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i); \
+ ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1); \
+ WTYPE val_lo = OP_LO((WTYPE)s1_lo, (WTYPE)s2_hi); \
+ WTYPE val_hi = OP_HI((WTYPE)s1_hi, (WTYPE)s2_lo); \
+ ETYPE res_lo = SAT_FN(val_lo, &sat); \
+ ETYPE res_hi = SAT_FN(val_hi, &sat); \
+ rd = INSERT(rd, res_lo, i); \
+ rd = INSERT(rd, res_hi, i + 1); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_XPAIR_AVG_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, \
+ INSERT, ELEMS, OP_LO, OP_HI) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i += 2) { \
+ ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1); \
+ ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i); \
+ ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1); \
+ ETYPE res_lo = (ETYPE)(OP_LO((WTYPE)s1_lo, (WTYPE)s2_hi) >> 1); \
+ ETYPE res_hi = (ETYPE)(OP_HI((WTYPE)s1_hi, (WTYPE)s2_lo) >> 1); \
+ rd = INSERT(rd, res_lo, i); \
+ rd = INSERT(rd, res_hi, i + 1); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_REDSUM(NAME, RTYPE, SUMTYPE, ETYPE, EXTRACT, ELEMS, \
+ INIT) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ SUMTYPE sum = (INIT); \
+ int elems = ELEMS(rs1); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ sum += e1; \
+ } \
+ \
+ return (RTYPE)sum; \
+}
+
+#define PSIMD_PAIR_LO(V, MASK, SHIFT) ((V) & (MASK))
+#define PSIMD_PAIR_HI(V, MASK, SHIFT) (((V) >> (SHIFT)) & (MASK))
+
+#define GEN_PSIMD_PAIR_PACK(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS, \
+ MASK, SHIFT, HI_SEL, LO_SEL) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = EXTRACT(rs1, i); \
+ ETYPE e2 = EXTRACT(rs2, i); \
+ ETYPE res = (HI_SEL(e2, MASK, SHIFT) << (SHIFT)) | \
+ LO_SEL(e1, MASK, SHIFT); \
+ rd = INSERT(rd, res, i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_PAIR_WORD(NAME, RS1_IDX, RS2_IDX) \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
+{ \
+ uint32_t e1 = EXTRACT32(rs1, RS1_IDX); \
+ uint32_t e2 = EXTRACT32(rs2, RS2_IDX); \
+ \
+ return ((uint64_t)e2 << 32) | e1; \
+}
+
+#define GEN_PSIMD_SIGN_EXTEND(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT, \
+ ELEMS, SCALE) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ STYPE e1 = (STYPE)EXTRACT(rs1, i * (SCALE)); \
+ rd = INSERT(rd, (DTYPE)e1, i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_ZIP(NAME, ETYPE, EXTRACT, ELEMS, BITS, START) \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
+{ \
+ uint64_t rd = 0; \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ ETYPE e1 = EXTRACT(rs1, (START) - i); \
+ ETYPE e2 = EXTRACT(rs2, (START) - i); \
+ rd = (rd << (2 * (BITS))) | ((uint64_t)e2 << (BITS)) | e1; \
+ } \
+ \
+ return rd; \
+}
+
+#define GEN_PSIMD_UNZIP(NAME, EXTRACT, ELEMS, BITS, OFFSET) \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
+{ \
+ uint64_t rd = 0; \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ uint64_t e1 = (uint64_t)EXTRACT(rs1, 2 * i + (OFFSET)) << \
+ ((BITS) * i); \
+ uint64_t e2 = (uint64_t)EXTRACT(rs2, 2 * i + (OFFSET)) << \
+ (32 + (BITS) * i); \
+ rd = rd | e2 | e1; \
+ } \
+ \
+ return rd; \
+}
+
+#define GEN_PSIMD_BIT_SELECT(NAME, MASK, TRUE_VAL, FALSE_VAL) \
+target_ulong HELPER(NAME)(CPURISCVState *env, target_ulong rs1, \
+ target_ulong rs2, target_ulong rd) \
+{ \
+ return (~(MASK) & (FALSE_VAL)) | ((MASK) & (TRUE_VAL)); \
+}
+
+#define GEN_PSIMD_NCLIP_PACK(NAME, ITYPE, OTYPE, EXTRACT, INSERT, ELEMS, \
+ SAT_FN) \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
+{ \
+ uint64_t rd = 0; \
+ int sat = 0; \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ ITYPE lo = (ITYPE)EXTRACT(rs1, i); \
+ ITYPE hi = (ITYPE)EXTRACT(rs2, i); \
+ OTYPE res_lo = SAT_FN(lo, &sat); \
+ OTYPE res_hi = SAT_FN(hi, &sat); \
+ \
+ rd = (uint64_t)INSERT(rd, res_lo, i); \
+ rd = (uint64_t)INSERT(rd, res_hi, i + (ELEMS)); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_CLS(NAME, RTYPE, UTYPE, CLRSB) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1) \
+{ \
+ return CLRSB((UTYPE)rs1); \
+}
+
+#define PSIMD_MUL_S32(A, B) ((int32_t)(A) * (int32_t)(B))
+#define PSIMD_MUL_SU16(A, B) ((int16_t)(A) * (uint16_t)(B))
+#define PSIMD_MUL_SU32(A, B) ((int32_t)(A) * (uint32_t)(B))
+#define PSIMD_MUL_U32(A, B) ((uint32_t)(A) * (uint32_t)(B))
+#define PSIMD_MUL_S64(A, B) ((int64_t)(A) * (int64_t)(B))
+#define PSIMD_MUL_SU64(A, B) ((int64_t)(A) * (uint64_t)(B))
+#define PSIMD_MUL_U64(A, B) ((uint64_t)(A) * (uint64_t)(B))
+
+#define GEN_PSIMD_MUL_HIGH(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, HTYPE, \
+ EXTRACT, INSERT, ELEMS, SHIFT, ROUND, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i); \
+ E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i); \
+ PTYPE prod = OP(e1, e2) + (ROUND); \
+ HTYPE high = (HTYPE)(prod >> (SHIFT)); \
+ rd = INSERT(rd, high, i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_MUL_HIGH_SEL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, \
+ HTYPE, EXTRACT1, EXTRACT2, INSERT, ELEMS, \
+ SCALE, OFFSET, SHIFT, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ E1TYPE e1 = (E1TYPE)EXTRACT1(rs1, i); \
+ E2TYPE e2 = (E2TYPE)EXTRACT2(rs2, i * (SCALE) + (OFFSET)); \
+ PTYPE prod = OP(e1, e2); \
+ HTYPE high = (HTYPE)(prod >> (SHIFT)); \
+ rd = INSERT(rd, high, i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_MUL_ELEM_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, \
+ OTYPE, EXTRACT, INSERT, ELEMS, SCALE, \
+ OFFSET1, OFFSET2, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1)); \
+ E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2)); \
+ PTYPE mul = OP(e1, e2); \
+ rd = INSERT(rd, (OTYPE)mul, i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_MUL_ELEM_SCALAR(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, \
+ EXTRACT, OFFSET1, OFFSET2, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ E1TYPE e1 = (E1TYPE)EXTRACT(rs1, OFFSET1); \
+ E2TYPE e2 = (E2TYPE)EXTRACT(rs2, OFFSET2); \
+ PTYPE mul = OP(e1, e2); \
+ \
+ return (RTYPE)mul; \
+}
+
+#define GEN_PSIMD_MUL_HIGH_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
+ HTYPE, OTYPE, EXTRACT, INSERT, ELEMS, \
+ SHIFT, ROUND, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i); \
+ E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i); \
+ DTYPE d = (DTYPE)EXTRACT(dest, i); \
+ PTYPE prod = OP(e1, e2) + (ROUND); \
+ HTYPE high = (HTYPE)(prod >> (SHIFT)); \
+ OTYPE res = (OTYPE)(high + d); \
+ rd = INSERT(rd, res, i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_MUL_HIGH_ACC_SEL(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, \
+ PTYPE, HTYPE, OTYPE, EXTRACT1, \
+ EXTRACT2, INSERT, ELEMS, SCALE, \
+ OFFSET, SHIFT, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ E1TYPE e1 = (E1TYPE)EXTRACT1(rs1, i); \
+ E2TYPE e2 = (E2TYPE)EXTRACT2(rs2, i * (SCALE) + (OFFSET)); \
+ DTYPE d = (DTYPE)EXTRACT1(dest, i); \
+ PTYPE prod = OP(e1, e2); \
+ HTYPE high = (HTYPE)(prod >> (SHIFT)); \
+ OTYPE res = (OTYPE)(high + d); \
+ rd = INSERT(rd, res, i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_MUL_ACC_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, \
+ PTYPE, OTYPE, EXTRACT, EXTRACTD, \
+ INSERT, ELEMS, SCALE, OFFSET1, \
+ OFFSET2, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1)); \
+ E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2)); \
+ DTYPE d = (DTYPE)EXTRACTD(dest, i); \
+ PTYPE mul = OP(e1, e2); \
+ rd = INSERT(rd, (OTYPE)(d + mul), i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_QMUL(NAME, RTYPE, ETYPE, PTYPE, OTYPE, EXTRACT, INSERT, \
+ ELEMS, SHIFT, ROUND, MINVAL, MAXVAL) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ int sat = 0; \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
+ ETYPE e2 = (ETYPE)EXTRACT(rs2, i); \
+ OTYPE result; \
+ \
+ if ((e1 == (ETYPE)(MINVAL)) && (e2 == (ETYPE)(MINVAL))) { \
+ sat = 1; \
+ result = (OTYPE)(MAXVAL); \
+ } else { \
+ PTYPE prod = (PTYPE)e1 * (PTYPE)e2 + (ROUND); \
+ result = (OTYPE)(prod >> (SHIFT)); \
+ } \
+ rd = INSERT(rd, result, i); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_QMUL_ACC_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, \
+ PTYPE, STYPE, OTYPE, EXTRACT, \
+ EXTRACTD, INSERT, ELEMS, SCALE, \
+ OFFSET1, OFFSET2, SHIFT, ROUND, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1)); \
+ E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2)); \
+ DTYPE d = (DTYPE)EXTRACTD(dest, i); \
+ PTYPE prod = OP(e1, e2) + (ROUND); \
+ STYPE scaled = (STYPE)(((__int128_t)prod) >> (SHIFT)); \
+ rd = INSERT(rd, (OTYPE)(d + scaled), i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_Q2ADD(NAME, RTYPE, ETYPE, PTYPE, STYPE, OTYPE, EXTRACT, \
+ INSERT, ELEMS, SCALE, SHIFT, ROUND, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE s1_0 = (ETYPE)EXTRACT(rs1, i * (SCALE)); \
+ ETYPE s1_1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + 1); \
+ ETYPE s2_0 = (ETYPE)EXTRACT(rs2, i * (SCALE)); \
+ ETYPE s2_1 = (ETYPE)EXTRACT(rs2, i * (SCALE) + 1); \
+ PTYPE prod0 = OP(s1_0, s2_0) + (ROUND); \
+ PTYPE prod1 = OP(s1_1, s2_1) + (ROUND); \
+ STYPE scaled0 = (STYPE)(((__int128_t)prod0) >> (SHIFT)); \
+ STYPE scaled1 = (STYPE)(((__int128_t)prod1) >> (SHIFT)); \
+ rd = INSERT(rd, (OTYPE)(scaled0 + scaled1), i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_Q2ADDA(NAME, RTYPE, ETYPE, DTYPE, PTYPE, STYPE, OTYPE, \
+ EXTRACT, EXTRACTD, INSERT, ELEMS, SCALE, \
+ SHIFT, ROUND, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ ETYPE s1_0 = (ETYPE)EXTRACT(rs1, i * (SCALE)); \
+ ETYPE s1_1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + 1); \
+ ETYPE s2_0 = (ETYPE)EXTRACT(rs2, i * (SCALE)); \
+ ETYPE s2_1 = (ETYPE)EXTRACT(rs2, i * (SCALE) + 1); \
+ DTYPE d = (DTYPE)EXTRACTD(dest, i); \
+ PTYPE prod0 = OP(s1_0, s2_0) + (ROUND); \
+ PTYPE prod1 = OP(s1_1, s2_1) + (ROUND); \
+ STYPE scaled0 = (STYPE)(((__int128_t)prod0) >> (SHIFT)); \
+ STYPE scaled1 = (STYPE)(((__int128_t)prod1) >> (SHIFT)); \
+ rd = INSERT(rd, (OTYPE)(d + scaled0 + scaled1), i); \
+ } \
+ return rd; \
+}
+
+#define PSIMD_COMB_ADD(D, A, B) ((D) + (A) + (B))
+#define PSIMD_COMB_SUB(D, A, B) ((D) + (A) - (B))
+
+#define GEN_PSIMD_2WAY_MUL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, OTYPE, \
+ EXTRACT, INSERT, ELEMS, SCALE, OFFSET10, \
+ OFFSET11, OFFSET20, OFFSET21, OP, COMBINE) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET10)); \
+ E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET11)); \
+ E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET20)); \
+ E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET21)); \
+ PTYPE prod0 = OP(s1_0, s2_0); \
+ PTYPE prod1 = OP(s1_1, s2_1); \
+ rd = INSERT(rd, (OTYPE)COMBINE(0, prod0, prod1), i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_2WAY_SAT_MUL(NAME, OFFSET10, OFFSET11, OFFSET20, \
+ OFFSET21) \
+target_ulong HELPER(NAME)(CPURISCVState *env, target_ulong rs1, \
+ target_ulong rs2) \
+{ \
+ target_ulong rd = 0; \
+ int sat = 0; \
+ \
+ for (int i = 0; i < ELEMS_W(rd); i++) { \
+ int16_t s1_0 = (int16_t)EXTRACT16(rs1, i * 2 + (OFFSET10)); \
+ int16_t s1_1 = (int16_t)EXTRACT16(rs1, i * 2 + (OFFSET11)); \
+ int16_t s2_0 = (int16_t)EXTRACT16(rs2, i * 2 + (OFFSET20)); \
+ int16_t s2_1 = (int16_t)EXTRACT16(rs2, i * 2 + (OFFSET21)); \
+ uint32_t result; \
+ \
+ if (s1_0 == INT16_MIN && s1_1 == INT16_MIN && \
+ s2_0 == INT16_MIN && s2_1 == INT16_MIN) { \
+ result = INT32_MAX; \
+ sat = 1; \
+ } else { \
+ int32_t prod0 = (int32_t)s1_0 * s2_0; \
+ int32_t prod1 = (int32_t)s1_1 * s2_1; \
+ result = (uint32_t)(prod0 + prod1); \
+ } \
+ rd = INSERT32(rd, result, i); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_2WAY_MUL_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
+ OTYPE, EXTRACT, EXTRACTD, INSERT, ELEMS, \
+ SCALE, OFFSET10, OFFSET11, OFFSET20, \
+ OFFSET21, OP, COMBINE) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET10)); \
+ E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET11)); \
+ E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET20)); \
+ E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET21)); \
+ DTYPE d = (DTYPE)EXTRACTD(dest, i); \
+ PTYPE prod0 = OP(s1_0, s2_0); \
+ PTYPE prod1 = OP(s1_1, s2_1); \
+ rd = INSERT(rd, (OTYPE)COMBINE(d, prod0, prod1), i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_4WAY_MUL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, OTYPE, \
+ EXTRACT, INSERT, ELEMS, SCALE, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ PTYPE prod0 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE)), \
+ (E2TYPE)EXTRACT(rs2, i * (SCALE))); \
+ PTYPE prod1 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 1), \
+ (E2TYPE)EXTRACT(rs2, i * (SCALE) + 1)); \
+ PTYPE prod2 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 2), \
+ (E2TYPE)EXTRACT(rs2, i * (SCALE) + 2)); \
+ PTYPE prod3 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 3), \
+ (E2TYPE)EXTRACT(rs2, i * (SCALE) + 3)); \
+ rd = INSERT(rd, (OTYPE)(prod0 + prod1 + prod2 + prod3), i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_4WAY_MUL_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
+ OTYPE, EXTRACT, EXTRACTD, INSERT, ELEMS, \
+ SCALE, OP) \
+RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
+{ \
+ RTYPE rd = 0; \
+ int elems = ELEMS(rd); \
+ \
+ for (int i = 0; i < elems; i++) { \
+ DTYPE d = (DTYPE)EXTRACTD(dest, i); \
+ PTYPE prod0 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE)), \
+ (E2TYPE)EXTRACT(rs2, i * (SCALE))); \
+ PTYPE prod1 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 1), \
+ (E2TYPE)EXTRACT(rs2, i * (SCALE) + 1)); \
+ PTYPE prod2 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 2), \
+ (E2TYPE)EXTRACT(rs2, i * (SCALE) + 2)); \
+ PTYPE prod3 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 3), \
+ (E2TYPE)EXTRACT(rs2, i * (SCALE) + 3)); \
+ rd = INSERT(rd, (OTYPE)(d + prod0 + prod1 + prod2 + prod3), i); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_WIDEN_BINOP(NAME, ETYPE, WTYPE, OTYPE, ELEMS, IBITS, \
+ OBITS, IMASK, OP) \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2) \
+{ \
+ uint64_t rd = 0; \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK)); \
+ ETYPE e2 = (ETYPE)((rs2 >> (i * (IBITS))) & (IMASK)); \
+ WTYPE res = OP((WTYPE)0, (WTYPE)e1, (WTYPE)e2); \
+ rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS)); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_WIDEN_BINOP_ACC(NAME, ETYPE, WTYPE, OTYPE, ELEMS, \
+ IBITS, OBITS, IMASK, OMASK, OP) \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2, \
+ uint64_t dest) \
+{ \
+ uint64_t rd = 0; \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK)); \
+ ETYPE e2 = (ETYPE)((rs2 >> (i * (IBITS))) & (IMASK)); \
+ WTYPE acc = (WTYPE)((dest >> (i * (OBITS))) & (OMASK)); \
+ WTYPE res = OP(acc, (WTYPE)e1, (WTYPE)e2); \
+ rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS)); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_WIDEN_MUL(NAME, E1TYPE, E2TYPE, PTYPE, OTYPE, ELEMS, \
+ EXTRACT, OBITS, OP) \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2) \
+{ \
+ uint64_t rd = 0; \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i); \
+ E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i); \
+ PTYPE prod = OP(e1, e2); \
+ rd |= ((uint64_t)(OTYPE)prod) << (i * (OBITS)); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_WIDEN_MUL_ACC(NAME, E1TYPE, E2TYPE, DTYPE, PTYPE, \
+ OTYPE, ELEMS, EXTRACT, EXTRACTD, OBITS, \
+ OP) \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2, \
+ uint64_t dest) \
+{ \
+ uint64_t rd = 0; \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i); \
+ E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i); \
+ DTYPE d = (DTYPE)EXTRACTD(dest, i); \
+ PTYPE prod = OP(e1, e2); \
+ rd |= ((uint64_t)(OTYPE)(d + prod)) << (i * (OBITS)); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_WIDEN_QMUL_ACC(NAME, ETYPE, DTYPE, PTYPE, STYPE, \
+ OTYPE, ELEMS, EXTRACT, EXTRACTD, SCALE, \
+ OFFSET, SHIFT, ROUND, OBITS, OP) \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2, \
+ uint64_t dest) \
+{ \
+ uint64_t rd = 0; \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ ETYPE e1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET)); \
+ ETYPE e2 = (ETYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET)); \
+ DTYPE d = (DTYPE)EXTRACTD(dest, i); \
+ PTYPE prod = OP(e1, e2) + (ROUND); \
+ STYPE scaled = (STYPE)(((__int128_t)prod) >> (SHIFT)); \
+ rd |= ((uint64_t)(OTYPE)(d + scaled)) << (i * (OBITS)); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_DW_2WAY_MUL(NAME, E1TYPE, E2TYPE, PTYPE, EXTRACT, \
+ OFFSET10, OFFSET11, OFFSET20, OFFSET21, \
+ OP, COMBINE) \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2) \
+{ \
+ E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, OFFSET10); \
+ E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, OFFSET11); \
+ E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, OFFSET20); \
+ E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, OFFSET21); \
+ PTYPE prod0 = OP(s1_0, s2_0); \
+ PTYPE prod1 = OP(s1_1, s2_1); \
+ \
+ return (uint64_t)COMBINE(0, prod0, prod1); \
+}
+
+#define GEN_PSIMD_DW_2WAY_MUL_ACC(NAME, E1TYPE, E2TYPE, DTYPE, PTYPE, \
+ EXTRACT, OFFSET10, OFFSET11, OFFSET20, \
+ OFFSET21, OP, COMBINE) \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2, \
+ uint64_t dest) \
+{ \
+ E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, OFFSET10); \
+ E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, OFFSET11); \
+ E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, OFFSET20); \
+ E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, OFFSET21); \
+ DTYPE d = (DTYPE)dest; \
+ PTYPE prod0 = OP(s1_0, s2_0); \
+ PTYPE prod1 = OP(s1_1, s2_1); \
+ \
+ return (uint64_t)COMBINE(d, prod0, prod1); \
+}
+
+#define GEN_PSIMD_WIDEN_SHIFT(NAME, ETYPE, WTYPE, OTYPE, ELEMS, IBITS, \
+ OBITS, IMASK, SHMASK) \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2) \
+{ \
+ uint64_t rd = 0; \
+ uint8_t shamt = rs2 & (SHMASK); \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK)); \
+ WTYPE res = (WTYPE)e1 << shamt; \
+ rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS)); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_DW_ZIP(NAME, EXTRACT, ELEMS, STRIDE, BITS) \
+uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2) \
+{ \
+ uint64_t rd = 0; \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ uint64_t e1 = (uint64_t)EXTRACT(rs1, i) << ((STRIDE) * i); \
+ uint64_t e2 = (uint64_t)EXTRACT(rs2, i) \
+ << ((STRIDE) * i + (BITS)); \
+ rd |= e2 | e1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_DW_REDSUM(NAME, SUMTYPE, INITTYPE, ETYPE, EXTRACT, \
+ ELEMS) \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1_lo, \
+ uint32_t rs1_hi, uint32_t rs2) \
+{ \
+ SUMTYPE sum = (INITTYPE)rs2; \
+ uint64_t s1 = ((uint64_t)rs1_hi << 32) | rs1_lo; \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ sum += (ETYPE)EXTRACT(s1, i); \
+ } \
+ return (uint32_t)sum; \
+}
+
+#define GEN_PSIMD_NARROW_SRL(NAME, ETYPE, OTYPE, ELEMS, IBITS, OBITS, \
+ IMASK, SHMASK) \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
+{ \
+ uint32_t rd = 0; \
+ uint8_t shift = shamt & (SHMASK); \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
+ OTYPE result = (OTYPE)(e1 >> shift); \
+ rd |= ((uint32_t)result) << (i * (OBITS)); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_NARROW_SRA_PACK(NAME, ETYPE, STYPE, OTYPE, ELEMS, \
+ IBITS, OBITS, IMASK, SHMASK) \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
+{ \
+ uint32_t rd = 0; \
+ uint8_t shift = shamt & (SHMASK); \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
+ STYPE shx = (STYPE)e1 >> shift; \
+ OTYPE result = (OTYPE)shx; \
+ rd |= ((uint32_t)result) << (i * (OBITS)); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_NARROW_RNDSRA_PACK(NAME, ETYPE, STYPE, OTYPE, ELEMS, \
+ IBITS, OBITS, IMASK, SHMASK, RMASK) \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
+{ \
+ uint32_t rd = 0; \
+ uint8_t shift = shamt & (SHMASK); \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
+ STYPE e1_s = (STYPE)e1; \
+ uint64_t shx = (((uint64_t)e1_s << 1) >> shift) & (RMASK); \
+ OTYPE result = (OTYPE)((shx + 1) >> 1); \
+ rd |= ((uint32_t)result) << (i * (OBITS)); \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_NCLIP_SIGNED_PACK(NAME, ETYPE, STYPE, CTYPE, OTYPE, \
+ ELEMS, IBITS, OBITS, IMASK, SHMASK, \
+ MIN, MAX, MIN_RES, MAX_RES) \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
+{ \
+ uint32_t rd = 0; \
+ uint8_t shift = shamt & (SHMASK); \
+ int sat = 0; \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
+ CTYPE shx = (CTYPE)((STYPE)e1 >> shift); \
+ OTYPE result; \
+ \
+ if (shx < (MIN)) { \
+ sat = 1; \
+ result = (MIN_RES); \
+ } else if (shx > (MAX)) { \
+ sat = 1; \
+ result = (MAX_RES); \
+ } else { \
+ result = (OTYPE)shx; \
+ } \
+ rd |= ((uint32_t)result) << (i * (OBITS)); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_NCLIPR_SIGNED_PACK(NAME, ETYPE, STYPE, CTYPE, OTYPE, \
+ ELEMS, IBITS, OBITS, IMASK, SHMASK, \
+ RMASK, MIN, MAX, MIN_RES, MAX_RES) \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
+{ \
+ uint32_t rd = 0; \
+ uint8_t shift = shamt & (SHMASK); \
+ int sat = 0; \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
+ STYPE e1_s = (STYPE)e1; \
+ uint64_t shx = (((uint64_t)e1_s << 1) >> shift) & (RMASK); \
+ CTYPE round_shx = (CTYPE)((shx + 1) >> 1); \
+ OTYPE result; \
+ \
+ if (round_shx < (MIN)) { \
+ sat = 1; \
+ result = (MIN_RES); \
+ } else if (round_shx > (MAX)) { \
+ sat = 1; \
+ result = (MAX_RES); \
+ } else { \
+ result = (OTYPE)round_shx; \
+ } \
+ rd |= ((uint32_t)result) << (i * (OBITS)); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_NCLIP_UNSIGNED_PACK(NAME, ETYPE, WTYPE, OTYPE, ELEMS, \
+ IBITS, OBITS, IMASK, SHMASK, MAX) \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
+{ \
+ uint32_t rd = 0; \
+ uint8_t shift = shamt & (SHMASK); \
+ int sat = 0; \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
+ WTYPE shx = (WTYPE)e1 >> shift; \
+ OTYPE result; \
+ \
+ if (shx > (MAX)) { \
+ sat = 1; \
+ result = (OTYPE)(MAX); \
+ } else { \
+ result = (OTYPE)shx; \
+ } \
+ rd |= ((uint32_t)result) << (i * (OBITS)); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_NCLIPR_UNSIGNED_PACK(NAME, ETYPE, WTYPE, OTYPE, ELEMS, \
+ IBITS, OBITS, IMASK, SHMASK, MAX) \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
+{ \
+ uint32_t rd = 0; \
+ uint8_t shift = shamt & (SHMASK); \
+ int sat = 0; \
+ \
+ for (int i = 0; i < (ELEMS); i++) { \
+ ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
+ WTYPE shx = ((WTYPE)e1 << 1) >> shift; \
+ WTYPE round_shx = (shx + 1) >> 1; \
+ OTYPE result; \
+ \
+ if (round_shx > (MAX)) { \
+ sat = 1; \
+ result = (OTYPE)(MAX); \
+ } else { \
+ result = (OTYPE)round_shx; \
+ } \
+ rd |= ((uint32_t)result) << (i * (OBITS)); \
+ } \
+ \
+ if (sat) { \
+ env->vxsat = 1; \
+ } \
+ return rd; \
+}
+
+#define GEN_PSIMD_NARROW_SRA(NAME) \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
+{ \
+ __int128_t s1_s128 = (__int128_t)((int64_t)s1); \
+ __int128_t s1_s96 = (s1_s128 << 32) >> 32; \
+ \
+ return (uint32_t)(s1_s96 >> (shamt & 0x3F)) & 0xFFFFFFFF; \
+}
+
+#define GEN_PSIMD_NARROW_RNDSRA(NAME) \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
+{ \
+ __int128_t s1_s128 = (__int128_t)((int64_t)s1); \
+ __int128_t s1_s96 = (s1_s128 << 32) >> 32; \
+ __uint128_t shx_97bit = ((__uint128_t)s1_s96 << 1); \
+ uint64_t shx = (uint64_t)(shx_97bit >> (shamt & 0x3F)) & 0x1FFFFFFFF; \
+ \
+ return (uint32_t)((shx + 1) >> 1); \
+}
+
+#define GEN_PSIMD_NARROW_ALIAS(NAME, TARGET) \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
+{ \
+ return HELPER(TARGET)(env, s1, shamt); \
+}
+
+typedef struct {
+ __uint128_t low;
+ uint8_t high;
+} PsImdUint129;
+
+static inline PsImdUint129 psimd_uint129_lshift1(__int128_t val)
+{
+ PsImdUint129 result;
+ __uint128_t uval = (__uint128_t)val;
+
+ result.low = uval << 1;
+ result.high = (uval >> 127) & 0x1;
+ return result;
+}
+
+static inline PsImdUint129 psimd_uint129_rshift(PsImdUint129 val,
+ uint32_t shamt)
+{
+ PsImdUint129 result;
+
+ if (shamt == 0) {
+ return val;
+ } else if (shamt >= 129) {
+ result.low = 0;
+ result.high = 0;
+ } else if (shamt == 128) {
+ result.low = val.high;
+ result.high = 0;
+ } else {
+ result.low = (val.low >> shamt) |
+ ((__uint128_t)val.high << (128 - shamt));
+ result.high = val.high >> shamt;
+ }
+ return result;
+}
+
+#define GEN_PSIMD_NCLIP(NAME) \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
+{ \
+ __int128_t s1_s128 = (__int128_t)((int64_t)s1); \
+ int64_t shx = (int64_t)(s1_s128 >> (shamt & 0x3F)); \
+ \
+ if (shx < -2147483648LL) { \
+ env->vxsat = 1; \
+ return 0x80000000U; \
+ } else if (shx > 2147483647LL) { \
+ env->vxsat = 1; \
+ return 0x7FFFFFFFU; \
+ } else { \
+ return (uint32_t)(shx & 0xFFFFFFFF); \
+ } \
+}
+
+#define GEN_PSIMD_NCLIPR(NAME) \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
+{ \
+ __int128_t s1_s128 = (__int128_t)((int64_t)s1); \
+ PsImdUint129 shx_129bit = psimd_uint129_lshift1(s1_s128); \
+ PsImdUint129 shx = psimd_uint129_rshift(shx_129bit, shamt & 0x3F); \
+ int64_t round_shx = (int64_t)((shx.low + 1) >> 1); \
+ \
+ if (round_shx < -2147483648LL) { \
+ env->vxsat = 1; \
+ return 0x80000000U; \
+ } else if (round_shx > 2147483647LL) { \
+ env->vxsat = 1; \
+ return 0x7FFFFFFFU; \
+ } else { \
+ return (uint32_t)round_shx; \
+ } \
+}
+
+#define GEN_PSIMD_NCLIPU(NAME) \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
+{ \
+ uint64_t shx = s1 >> (shamt & 0x3F); \
+ \
+ if (shx > 4294967295ULL) { \
+ env->vxsat = 1; \
+ return 0xFFFFFFFFU; \
+ } else { \
+ return (uint32_t)(shx & 0xFFFFFFFF); \
+ } \
+}
+
+#define GEN_PSIMD_NCLIPRU(NAME) \
+uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
+{ \
+ __uint128_t shx_65bit = (__uint128_t)s1 << 1; \
+ __uint128_t shx = shx_65bit >> (shamt & 0x3F); \
+ uint64_t round_shx = (shx + 1) >> 1; \
+ \
+ if (round_shx > 4294967295ULL) { \
+ env->vxsat = 1; \
+ return 0xFFFFFFFFU; \
+ } else { \
+ return (uint32_t)(round_shx & 0xFFFFFFFF); \
+ } \
+}
+
+/* Basic addition operations (non-saturating) */
+
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework
2026-07-17 10:06 ` [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework Molly Chen
@ 2026-07-26 19:53 ` Daniel Henrique Barboza
2026-07-27 6:16 ` Nutty.Liu
2026-07-29 9:01 ` Chao Liu
2 siblings, 0 replies; 31+ messages in thread
From: Daniel Henrique Barboza @ 2026-07-26 19:53 UTC (permalink / raw)
To: Molly Chen, palmer, alistair.francis, liwei1518, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: qemu-riscv, qemu-devel
On 7/17/2026 7:06 AM, Molly Chen wrote:
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
> ---
There might be some code reduction opportunities in these helpers but
I'm afraid it'll come at a cost of readability. I think this is fine
for now.
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> target/riscv/tcg/meson.build | 3 +-
> target/riscv/tcg/psimd_helper.c | 1656 +++++++++++++++++++++++++++++++
> 2 files changed, 1658 insertions(+), 1 deletion(-)
> create mode 100644 target/riscv/tcg/psimd_helper.c
>
> diff --git a/target/riscv/tcg/meson.build b/target/riscv/tcg/meson.build
> index a05ab642f41..cc438d7c0d2 100644
> --- a/target/riscv/tcg/meson.build
> +++ b/target/riscv/tcg/meson.build
> @@ -15,7 +15,8 @@ riscv_ss.add(files(
> 'vcrypto_helper.c',
> 'vector_helper.c',
> 'vector_internals.c',
> - 'zce_helper.c'))
> + 'zce_helper.c',
> + 'psimd_helper.c'))
>
>
> riscv_system_ss.add(files(
> diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
> new file mode 100644
> index 00000000000..2948bbb2a86
> --- /dev/null
> +++ b/target/riscv/tcg/psimd_helper.c
> @@ -0,0 +1,1656 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/* RISC-V Packed SIMD Extension Helpers for QEMU. */
> +/* Copyright (C) 2026 ISRC ISCAS. */
> +
> +#include "qemu/osdep.h"
> +#include "cpu.h"
> +#include "qemu/host-utils.h"
> +#include "exec/helper-proto.h"
> +#include "fpu/softfloat.h"
> +#include "internals.h"
> +
> +
> +/* Helper macros */
> +
> +/* Element count calculations */
> +#define ELEMS_B(target) (sizeof(target) * 8 / 8) /* byte elements count */
> +#define ELEMS_H(target) (sizeof(target) * 8 / 16)
> +#define ELEMS_W(target) (sizeof(target) * 8 / 32) /* word elements count */
> +#define ELEMS_D(target) (sizeof(target) * 8 / 64)
> +
> +/* Element extraction macros - unsigned to avoid sign extension */
> +#define EXTRACT8(val, idx) (((val) >> ((idx) * 8)) & 0xFF)
> +#define EXTRACT16(val, idx) (((val) >> ((idx) * 16)) & 0xFFFF)
> +#define EXTRACT32(val, idx) (((val) >> ((idx) * 32)) & 0xFFFFFFFF)
> +#define EXTRACT64(val, idx) (((val) >> ((idx) * 64)) & 0xFFFFFFFFFFFFFFFFULL)
> +
> +/* Element insertion macros */
> +#define INSERT8(val, res, idx) \
> + ((val) | ((target_ulong)(uint8_t)(res) << ((idx) * 8)))
> +#define INSERT16(val, res, idx) \
> + ((val) | ((target_ulong)(uint16_t)(res) << ((idx) * 16)))
> +#define INSERT32(val, res, idx) \
> + ((val) | ((target_ulong)(uint32_t)(res) << ((idx) * 32)))
> +#define INSERT32_64(val, res, idx) \
> + ((val) | ((uint64_t)(uint32_t)(res) << ((idx) * 32)))
> +#define INSERT64(val, res, idx) \
> + ((val) | ((uint64_t)(res) << ((idx) * 64)))
> +
> +/* Saturation constants */
> +static const int8_t SAT_MAX_B = 127;
> +static const int8_t SAT_MIN_B = -128;
> +static const int16_t SAT_MAX_H = 32767;
> +static const int16_t SAT_MIN_H = -32768;
> +static const int32_t SAT_MAX_W = 2147483647;
> +static const int32_t SAT_MIN_W = -2147483648LL;
> +static const uint8_t USAT_MAX_B = 255;
> +static const uint16_t USAT_MAX_H = 65535;
> +static const uint32_t USAT_MAX_W = 4294967295U;
> +
> +
> +/* Saturation helper functions */
> +
> +/**
> + * Signed saturation for 8-bit elements
> + * Returns saturated value and sets *sat if saturation occurred
> + */
> +static inline int8_t signed_saturate_b(int32_t val, int *sat)
> +{
> + if (val > SAT_MAX_B) {
> + *sat = 1;
> + return SAT_MAX_B;
> + }
> + if (val < SAT_MIN_B) {
> + *sat = 1;
> + return SAT_MIN_B;
> + }
> + return (int8_t)val;
> +}
> +
> +/**
> + * Signed saturation for 16-bit elements
> + */
> +static inline int16_t signed_saturate_h(int32_t val, int *sat)
> +{
> + if (val > SAT_MAX_H) {
> + *sat = 1;
> + return SAT_MAX_H;
> + }
> + if (val < SAT_MIN_H) {
> + *sat = 1;
> + return SAT_MIN_H;
> + }
> + return (int16_t)val;
> +}
> +
> +/**
> + * Signed saturation for 32-bit elements
> + */
> +static inline int32_t signed_saturate_w(int64_t val, int *sat)
> +{
> + if (val > SAT_MAX_W) {
> + *sat = 1;
> + return SAT_MAX_W;
> + }
> + if (val < SAT_MIN_W) {
> + *sat = 1;
> + return SAT_MIN_W;
> + }
> + return (int32_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 8-bit elements
> + */
> +static inline uint8_t unsigned_saturate_b(uint32_t val, int *sat)
> +{
> + if (val > USAT_MAX_B) {
> + *sat = 1;
> + return USAT_MAX_B;
> + }
> + return (uint8_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 16-bit elements
> + */
> +static inline uint16_t unsigned_saturate_h(uint32_t val, int *sat)
> +{
> + if (val > USAT_MAX_H) {
> + *sat = 1;
> + return USAT_MAX_H;
> + }
> + return (uint16_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 32-bit elements
> + */
> +static inline uint32_t unsigned_saturate_w(uint64_t val, int *sat)
> +{
> + if (val > USAT_MAX_W) {
> + *sat = 1;
> + return USAT_MAX_W;
> + }
> + return (uint32_t)val;
> +}
> +
> +static inline target_ulong psimd_abdsumu_b(target_ulong rs1,
> + target_ulong rs2,
> + target_ulong sum)
> +{
> + int elems = ELEMS_B(rs1);
> +
> + for (int i = 0; i < elems; i++) {
> + uint8_t e1 = EXTRACT8(rs1, i);
> + uint8_t e2 = EXTRACT8(rs2, i);
> + uint8_t diff = (e1 > e2) ? (e1 - e2) : (e2 - e1);
> + sum += diff;
> + }
> +
> + return sum;
> +}
> +
> +#define PSIMD_DO_ADD(N, M) ((N) + (M))
> +#define PSIMD_DO_SUB(N, M) ((N) - (M))
> +#define PSIMD_DO_ABD(N, M) ((N) >= (M) ? (N) - (M) : (M) - (N))
> +#define PSIMD_DO_EQ_MASK(N, M) ((N) == (M) ? -1 : 0)
> +#define PSIMD_DO_LT_MASK(N, M) ((N) < (M) ? -1 : 0)
> +#define PSIMD_DO_MIN(N, M) ((N) < (M) ? (N) : (M))
> +#define PSIMD_DO_MAX(N, M) ((N) > (M) ? (N) : (M))
> +#define PSIMD_DO_SLL(N, M) ((N) << (M))
> +#define PSIMD_DO_SRL(N, M) ((N) >> (M))
> +#define PSIMD_DO_SRA(N, M) ((N) >> (M))
> +
> +#define GEN_PSIMD_BINOP(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT, \
> + ELEMS, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + STYPE e1 = (STYPE)EXTRACT(rs1, i); \
> + STYPE e2 = (STYPE)EXTRACT(rs2, i); \
> + DTYPE res = (DTYPE)OP(e1, e2); \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_BINOP_SCALAR(NAME, RTYPE, ETYPE, EXTRACT, INSERT, \
> + ELEMS, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + ETYPE e2 = (ETYPE)EXTRACT(rs2, 0); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res = OP(e1, e2); \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_SHIFTOP(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT, \
> + ELEMS, SHMASK, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + uint8_t shamt = rs2 & (SHMASK); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + STYPE e1 = (STYPE)EXTRACT(rs1, i); \
> + DTYPE res = (DTYPE)OP(e1, shamt); \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_SAT_SHIFTOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, SHMASK, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + uint8_t shamt = rs2 & (SHMASK); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + WTYPE shifted = (WTYPE)e1 << shamt; \
> + ETYPE res = SAT_FN(shifted, &sat); \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_ROUND_SRAI(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, SHMASK) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + uint8_t shamt = rs2 & (SHMASK); \
> + \
> + if (shamt == 0) { \
> + return rs1; \
> + } \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + WTYPE rounded = (((WTYPE)e1 >> (shamt - 1)) + 1) >> 1; \
> + rd = INSERT(rd, (ETYPE)rounded, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_SAT_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, OP, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE e2 = (ETYPE)EXTRACT(rs2, i); \
> + WTYPE val = OP((WTYPE)e1, (WTYPE)e2); \
> + ETYPE res = SAT_FN(val, &sat); \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_USUB_SAT(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE e2 = (ETYPE)EXTRACT(rs2, i); \
> + ETYPE res = (e1 >= e2) ? (e1 - e2) : 0; \
> + if (e1 < e2) { \
> + sat = 1; \
> + } \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_AVG_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + WTYPE e1 = (WTYPE)(ETYPE)EXTRACT(rs1, i); \
> + WTYPE e2 = (WTYPE)(ETYPE)EXTRACT(rs2, i); \
> + ETYPE res = (ETYPE)(OP(e1, e2) >> 1); \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_SHADD(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS, \
> + SHAMT) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE e2 = (ETYPE)EXTRACT(rs2, i); \
> + ETYPE res = (e1 << (SHAMT)) + e2; \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_SAT_SHADD(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, SHAMT, SH_MIN, SH_MAX, SAT_MIN, \
> + SAT_MAX, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE e2 = (ETYPE)EXTRACT(rs2, i); \
> + WTYPE shifted; \
> + \
> + if (e1 > (SH_MAX) || e1 < (SH_MIN)) { \
> + shifted = (e1 < 0) ? (SAT_MIN) : (SAT_MAX); \
> + sat = 1; \
> + } else { \
> + shifted = (WTYPE)e1 << (SHAMT); \
> + } \
> + \
> + WTYPE sum = shifted + e2; \
> + ETYPE res = SAT_FN(sum, &sat); \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_SATI(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, IMMMASK) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE imm) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int range = (imm & (IMMMASK)) + 1; \
> + WTYPE max = ((WTYPE)1 << (range - 1)) - 1; \
> + WTYPE min = -((WTYPE)1 << (range - 1)); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res; \
> + \
> + if (e1 > max) { \
> + res = max; \
> + sat = 1; \
> + } else if (e1 < min) { \
> + res = min; \
> + sat = 1; \
> + } else { \
> + res = e1; \
> + } \
> + \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_USATI(NAME, RTYPE, ETYPE, UTYPE, WTYPE, EXTRACT, \
> + INSERT, ELEMS, ONE) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE imm) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + WTYPE max = ((WTYPE)(ONE) << imm) - 1; \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res; \
> + \
> + if (e1 < 0) { \
> + res = 0; \
> + sat = 1; \
> + } else if ((UTYPE)e1 > max) { \
> + res = max; \
> + sat = 1; \
> + } else { \
> + res = e1; \
> + } \
> + \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_ABS(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS, \
> + MINVAL, MAXVAL) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res; \
> + \
> + if (e1 == (MINVAL)) { \
> + res = (MAXVAL); \
> + sat = 1; \
> + } else if (e1 < 0) { \
> + res = -e1; \
> + } else { \
> + res = e1; \
> + } \
> + \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_SCALAR_ABS(NAME, RTYPE, STYPE, UTYPE) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1) \
> +{ \
> + STYPE value = (STYPE)rs1; \
> + UTYPE result = (UTYPE)value; \
> + \
> + if (value < 0) { \
> + result = (UTYPE)0 - result; \
> + } \
> + return (RTYPE)(STYPE)result; \
> +}
> +
> +#define GEN_PSIMD_VAR_SSHA(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, BITS, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + int8_t shamt = (int8_t)(rs2 & 0xff); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res; \
> + \
> + if (shamt >= 0) { \
> + WTYPE shifted = (WTYPE)e1 << shamt; \
> + res = SAT_FN(shifted, &sat); \
> + } else { \
> + int right = -shamt; \
> + if (right >= (BITS)) { \
> + res = (e1 < 0) ? -1 : 0; \
> + } else { \
> + res = e1 >> right; \
> + } \
> + } \
> + \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_VAR_SSHAR(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, BITS, SAT_MIN, SAT_MAX, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + int8_t shamt = (int8_t)(rs2 & 0xff); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res; \
> + \
> + if (shamt >= 0) { \
> + if (shamt >= (BITS)) { \
> + if (e1 == 0) { \
> + res = 0; \
> + } else if (e1 > 0) { \
> + res = (SAT_MAX); \
> + sat = 1; \
> + } else { \
> + res = (SAT_MIN); \
> + sat = 1; \
> + } \
> + } else { \
> + WTYPE shifted = (WTYPE)e1 * ((WTYPE)1 << shamt); \
> + res = SAT_FN(shifted, &sat); \
> + } \
> + } else { \
> + int right = -shamt; \
> + if (right >= (BITS)) { \
> + res = 0; \
> + } else { \
> + WTYPE rounded = ((e1 >> (right - 1)) + 1) >> 1; \
> + res = (ETYPE)rounded; \
> + } \
> + } \
> + \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_VAR_USHL(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, BITS, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + int8_t shamt = (int8_t)(rs2 & 0xff); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res; \
> + \
> + if (shamt >= 0) { \
> + WTYPE shifted = (shamt >= (BITS)) ? \
> + ((WTYPE)e1 << (BITS)) : \
> + ((WTYPE)e1 << shamt); \
> + res = SAT_FN(shifted, &sat); \
> + } else { \
> + int right = -shamt; \
> + if (right >= (BITS)) { \
> + res = 0; \
> + } else { \
> + res = e1 >> right; \
> + } \
> + } \
> + \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_VAR_USHLR(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, BITS, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + int8_t shamt = (int8_t)(rs2 & 0xff); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res; \
> + \
> + if (shamt >= 0) { \
> + WTYPE shifted = (shamt >= (BITS)) ? \
> + ((WTYPE)e1 << (BITS)) : \
> + ((WTYPE)e1 << shamt); \
> + res = SAT_FN(shifted, &sat); \
> + } else { \
> + int right = -shamt; \
> + if (right > (BITS)) { \
> + res = 0; \
> + } else { \
> + WTYPE rounded = ((WTYPE)e1 >> (right - 1)) + 1; \
> + res = (ETYPE)(rounded >> 1); \
> + } \
> + } \
> + \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define PSIMD_DO_SRA64(A, B) ((A) >> (B))
> +#define PSIMD_DO_RNDSRA64(A, B) \
> + ((int64_t)((((__int128_t)(A) >> ((B) - 1)) + 1) >> 1))
> +
> +#define GEN_PSIMD_VAR_SRA64(NAME, RIGHT_OP) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
> +{ \
> + int64_t a = (int64_t)rs1; \
> + int8_t shamt = (int8_t)(rs2 & 0xff); \
> + \
> + if (shamt >= 0) { \
> + return (uint64_t)(a << shamt); \
> + } \
> + \
> + int right = -shamt; \
> + if (right >= 64) { \
> + return (a < 0) ? (uint64_t)-1 : 0; \
> + } \
> + return (uint64_t)RIGHT_OP(a, right); \
> +}
> +
> +#define PSIMD_DO_SRL64(A, B) (((B) >= 64) ? 0 : ((A) >> (B)))
> +#define PSIMD_DO_RNDSRL64(A, B) \
> + (((B) > 64) ? 0 : ((((A) >> ((B) - 1)) + 1) >> 1))
> +
> +#define GEN_PSIMD_VAR_SRL64(NAME, RIGHT_OP) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
> +{ \
> + int8_t shamt = (int8_t)(rs2 & 0xff); \
> + \
> + if (shamt < 0) { \
> + return RIGHT_OP(rs1, -shamt); \
> + } \
> + return (shamt >= 64) ? 0 : (rs1 << shamt); \
> +}
> +
> +#define GEN_PSIMD_XPAIR_BINOP(NAME, RTYPE, ETYPE, EXTRACT, INSERT, \
> + ELEMS, OP_LO, OP_HI) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i += 2) { \
> + ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1); \
> + ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i); \
> + ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1); \
> + ETYPE res_lo = OP_LO(s1_lo, s2_hi); \
> + ETYPE res_hi = OP_HI(s1_hi, s2_lo); \
> + rd = INSERT(rd, res_lo, i); \
> + rd = INSERT(rd, res_hi, i + 1); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_XPAIR_SAT_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, \
> + INSERT, ELEMS, OP_LO, OP_HI, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i += 2) { \
> + ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1); \
> + ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i); \
> + ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1); \
> + WTYPE val_lo = OP_LO((WTYPE)s1_lo, (WTYPE)s2_hi); \
> + WTYPE val_hi = OP_HI((WTYPE)s1_hi, (WTYPE)s2_lo); \
> + ETYPE res_lo = SAT_FN(val_lo, &sat); \
> + ETYPE res_hi = SAT_FN(val_hi, &sat); \
> + rd = INSERT(rd, res_lo, i); \
> + rd = INSERT(rd, res_hi, i + 1); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_XPAIR_AVG_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, \
> + INSERT, ELEMS, OP_LO, OP_HI) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i += 2) { \
> + ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1); \
> + ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i); \
> + ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1); \
> + ETYPE res_lo = (ETYPE)(OP_LO((WTYPE)s1_lo, (WTYPE)s2_hi) >> 1); \
> + ETYPE res_hi = (ETYPE)(OP_HI((WTYPE)s1_hi, (WTYPE)s2_lo) >> 1); \
> + rd = INSERT(rd, res_lo, i); \
> + rd = INSERT(rd, res_hi, i + 1); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_REDSUM(NAME, RTYPE, SUMTYPE, ETYPE, EXTRACT, ELEMS, \
> + INIT) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + SUMTYPE sum = (INIT); \
> + int elems = ELEMS(rs1); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + sum += e1; \
> + } \
> + \
> + return (RTYPE)sum; \
> +}
> +
> +#define PSIMD_PAIR_LO(V, MASK, SHIFT) ((V) & (MASK))
> +#define PSIMD_PAIR_HI(V, MASK, SHIFT) (((V) >> (SHIFT)) & (MASK))
> +
> +#define GEN_PSIMD_PAIR_PACK(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS, \
> + MASK, SHIFT, HI_SEL, LO_SEL) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = EXTRACT(rs1, i); \
> + ETYPE e2 = EXTRACT(rs2, i); \
> + ETYPE res = (HI_SEL(e2, MASK, SHIFT) << (SHIFT)) | \
> + LO_SEL(e1, MASK, SHIFT); \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_PAIR_WORD(NAME, RS1_IDX, RS2_IDX) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
> +{ \
> + uint32_t e1 = EXTRACT32(rs1, RS1_IDX); \
> + uint32_t e2 = EXTRACT32(rs2, RS2_IDX); \
> + \
> + return ((uint64_t)e2 << 32) | e1; \
> +}
> +
> +#define GEN_PSIMD_SIGN_EXTEND(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT, \
> + ELEMS, SCALE) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + STYPE e1 = (STYPE)EXTRACT(rs1, i * (SCALE)); \
> + rd = INSERT(rd, (DTYPE)e1, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_ZIP(NAME, ETYPE, EXTRACT, ELEMS, BITS, START) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = EXTRACT(rs1, (START) - i); \
> + ETYPE e2 = EXTRACT(rs2, (START) - i); \
> + rd = (rd << (2 * (BITS))) | ((uint64_t)e2 << (BITS)) | e1; \
> + } \
> + \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_UNZIP(NAME, EXTRACT, ELEMS, BITS, OFFSET) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + uint64_t e1 = (uint64_t)EXTRACT(rs1, 2 * i + (OFFSET)) << \
> + ((BITS) * i); \
> + uint64_t e2 = (uint64_t)EXTRACT(rs2, 2 * i + (OFFSET)) << \
> + (32 + (BITS) * i); \
> + rd = rd | e2 | e1; \
> + } \
> + \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_BIT_SELECT(NAME, MASK, TRUE_VAL, FALSE_VAL) \
> +target_ulong HELPER(NAME)(CPURISCVState *env, target_ulong rs1, \
> + target_ulong rs2, target_ulong rd) \
> +{ \
> + return (~(MASK) & (FALSE_VAL)) | ((MASK) & (TRUE_VAL)); \
> +}
> +
> +#define GEN_PSIMD_NCLIP_PACK(NAME, ITYPE, OTYPE, EXTRACT, INSERT, ELEMS, \
> + SAT_FN) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
> +{ \
> + uint64_t rd = 0; \
> + int sat = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ITYPE lo = (ITYPE)EXTRACT(rs1, i); \
> + ITYPE hi = (ITYPE)EXTRACT(rs2, i); \
> + OTYPE res_lo = SAT_FN(lo, &sat); \
> + OTYPE res_hi = SAT_FN(hi, &sat); \
> + \
> + rd = (uint64_t)INSERT(rd, res_lo, i); \
> + rd = (uint64_t)INSERT(rd, res_hi, i + (ELEMS)); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_CLS(NAME, RTYPE, UTYPE, CLRSB) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1) \
> +{ \
> + return CLRSB((UTYPE)rs1); \
> +}
> +
> +#define PSIMD_MUL_S32(A, B) ((int32_t)(A) * (int32_t)(B))
> +#define PSIMD_MUL_SU16(A, B) ((int16_t)(A) * (uint16_t)(B))
> +#define PSIMD_MUL_SU32(A, B) ((int32_t)(A) * (uint32_t)(B))
> +#define PSIMD_MUL_U32(A, B) ((uint32_t)(A) * (uint32_t)(B))
> +#define PSIMD_MUL_S64(A, B) ((int64_t)(A) * (int64_t)(B))
> +#define PSIMD_MUL_SU64(A, B) ((int64_t)(A) * (uint64_t)(B))
> +#define PSIMD_MUL_U64(A, B) ((uint64_t)(A) * (uint64_t)(B))
> +
> +#define GEN_PSIMD_MUL_HIGH(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, HTYPE, \
> + EXTRACT, INSERT, ELEMS, SHIFT, ROUND, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i); \
> + PTYPE prod = OP(e1, e2) + (ROUND); \
> + HTYPE high = (HTYPE)(prod >> (SHIFT)); \
> + rd = INSERT(rd, high, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_MUL_HIGH_SEL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, \
> + HTYPE, EXTRACT1, EXTRACT2, INSERT, ELEMS, \
> + SCALE, OFFSET, SHIFT, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT1(rs1, i); \
> + E2TYPE e2 = (E2TYPE)EXTRACT2(rs2, i * (SCALE) + (OFFSET)); \
> + PTYPE prod = OP(e1, e2); \
> + HTYPE high = (HTYPE)(prod >> (SHIFT)); \
> + rd = INSERT(rd, high, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_MUL_ELEM_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, \
> + OTYPE, EXTRACT, INSERT, ELEMS, SCALE, \
> + OFFSET1, OFFSET2, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1)); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2)); \
> + PTYPE mul = OP(e1, e2); \
> + rd = INSERT(rd, (OTYPE)mul, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_MUL_ELEM_SCALAR(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, \
> + EXTRACT, OFFSET1, OFFSET2, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, OFFSET1); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, OFFSET2); \
> + PTYPE mul = OP(e1, e2); \
> + \
> + return (RTYPE)mul; \
> +}
> +
> +#define GEN_PSIMD_MUL_HIGH_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> + HTYPE, OTYPE, EXTRACT, INSERT, ELEMS, \
> + SHIFT, ROUND, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i); \
> + DTYPE d = (DTYPE)EXTRACT(dest, i); \
> + PTYPE prod = OP(e1, e2) + (ROUND); \
> + HTYPE high = (HTYPE)(prod >> (SHIFT)); \
> + OTYPE res = (OTYPE)(high + d); \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_MUL_HIGH_ACC_SEL(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, \
> + PTYPE, HTYPE, OTYPE, EXTRACT1, \
> + EXTRACT2, INSERT, ELEMS, SCALE, \
> + OFFSET, SHIFT, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT1(rs1, i); \
> + E2TYPE e2 = (E2TYPE)EXTRACT2(rs2, i * (SCALE) + (OFFSET)); \
> + DTYPE d = (DTYPE)EXTRACT1(dest, i); \
> + PTYPE prod = OP(e1, e2); \
> + HTYPE high = (HTYPE)(prod >> (SHIFT)); \
> + OTYPE res = (OTYPE)(high + d); \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_MUL_ACC_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, \
> + PTYPE, OTYPE, EXTRACT, EXTRACTD, \
> + INSERT, ELEMS, SCALE, OFFSET1, \
> + OFFSET2, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1)); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2)); \
> + DTYPE d = (DTYPE)EXTRACTD(dest, i); \
> + PTYPE mul = OP(e1, e2); \
> + rd = INSERT(rd, (OTYPE)(d + mul), i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_QMUL(NAME, RTYPE, ETYPE, PTYPE, OTYPE, EXTRACT, INSERT, \
> + ELEMS, SHIFT, ROUND, MINVAL, MAXVAL) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE e2 = (ETYPE)EXTRACT(rs2, i); \
> + OTYPE result; \
> + \
> + if ((e1 == (ETYPE)(MINVAL)) && (e2 == (ETYPE)(MINVAL))) { \
> + sat = 1; \
> + result = (OTYPE)(MAXVAL); \
> + } else { \
> + PTYPE prod = (PTYPE)e1 * (PTYPE)e2 + (ROUND); \
> + result = (OTYPE)(prod >> (SHIFT)); \
> + } \
> + rd = INSERT(rd, result, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_QMUL_ACC_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, \
> + PTYPE, STYPE, OTYPE, EXTRACT, \
> + EXTRACTD, INSERT, ELEMS, SCALE, \
> + OFFSET1, OFFSET2, SHIFT, ROUND, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1)); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2)); \
> + DTYPE d = (DTYPE)EXTRACTD(dest, i); \
> + PTYPE prod = OP(e1, e2) + (ROUND); \
> + STYPE scaled = (STYPE)(((__int128_t)prod) >> (SHIFT)); \
> + rd = INSERT(rd, (OTYPE)(d + scaled), i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_Q2ADD(NAME, RTYPE, ETYPE, PTYPE, STYPE, OTYPE, EXTRACT, \
> + INSERT, ELEMS, SCALE, SHIFT, ROUND, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE s1_0 = (ETYPE)EXTRACT(rs1, i * (SCALE)); \
> + ETYPE s1_1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + 1); \
> + ETYPE s2_0 = (ETYPE)EXTRACT(rs2, i * (SCALE)); \
> + ETYPE s2_1 = (ETYPE)EXTRACT(rs2, i * (SCALE) + 1); \
> + PTYPE prod0 = OP(s1_0, s2_0) + (ROUND); \
> + PTYPE prod1 = OP(s1_1, s2_1) + (ROUND); \
> + STYPE scaled0 = (STYPE)(((__int128_t)prod0) >> (SHIFT)); \
> + STYPE scaled1 = (STYPE)(((__int128_t)prod1) >> (SHIFT)); \
> + rd = INSERT(rd, (OTYPE)(scaled0 + scaled1), i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_Q2ADDA(NAME, RTYPE, ETYPE, DTYPE, PTYPE, STYPE, OTYPE, \
> + EXTRACT, EXTRACTD, INSERT, ELEMS, SCALE, \
> + SHIFT, ROUND, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE s1_0 = (ETYPE)EXTRACT(rs1, i * (SCALE)); \
> + ETYPE s1_1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + 1); \
> + ETYPE s2_0 = (ETYPE)EXTRACT(rs2, i * (SCALE)); \
> + ETYPE s2_1 = (ETYPE)EXTRACT(rs2, i * (SCALE) + 1); \
> + DTYPE d = (DTYPE)EXTRACTD(dest, i); \
> + PTYPE prod0 = OP(s1_0, s2_0) + (ROUND); \
> + PTYPE prod1 = OP(s1_1, s2_1) + (ROUND); \
> + STYPE scaled0 = (STYPE)(((__int128_t)prod0) >> (SHIFT)); \
> + STYPE scaled1 = (STYPE)(((__int128_t)prod1) >> (SHIFT)); \
> + rd = INSERT(rd, (OTYPE)(d + scaled0 + scaled1), i); \
> + } \
> + return rd; \
> +}
> +
> +#define PSIMD_COMB_ADD(D, A, B) ((D) + (A) + (B))
> +#define PSIMD_COMB_SUB(D, A, B) ((D) + (A) - (B))
> +
> +#define GEN_PSIMD_2WAY_MUL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, OTYPE, \
> + EXTRACT, INSERT, ELEMS, SCALE, OFFSET10, \
> + OFFSET11, OFFSET20, OFFSET21, OP, COMBINE) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET10)); \
> + E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET11)); \
> + E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET20)); \
> + E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET21)); \
> + PTYPE prod0 = OP(s1_0, s2_0); \
> + PTYPE prod1 = OP(s1_1, s2_1); \
> + rd = INSERT(rd, (OTYPE)COMBINE(0, prod0, prod1), i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_2WAY_SAT_MUL(NAME, OFFSET10, OFFSET11, OFFSET20, \
> + OFFSET21) \
> +target_ulong HELPER(NAME)(CPURISCVState *env, target_ulong rs1, \
> + target_ulong rs2) \
> +{ \
> + target_ulong rd = 0; \
> + int sat = 0; \
> + \
> + for (int i = 0; i < ELEMS_W(rd); i++) { \
> + int16_t s1_0 = (int16_t)EXTRACT16(rs1, i * 2 + (OFFSET10)); \
> + int16_t s1_1 = (int16_t)EXTRACT16(rs1, i * 2 + (OFFSET11)); \
> + int16_t s2_0 = (int16_t)EXTRACT16(rs2, i * 2 + (OFFSET20)); \
> + int16_t s2_1 = (int16_t)EXTRACT16(rs2, i * 2 + (OFFSET21)); \
> + uint32_t result; \
> + \
> + if (s1_0 == INT16_MIN && s1_1 == INT16_MIN && \
> + s2_0 == INT16_MIN && s2_1 == INT16_MIN) { \
> + result = INT32_MAX; \
> + sat = 1; \
> + } else { \
> + int32_t prod0 = (int32_t)s1_0 * s2_0; \
> + int32_t prod1 = (int32_t)s1_1 * s2_1; \
> + result = (uint32_t)(prod0 + prod1); \
> + } \
> + rd = INSERT32(rd, result, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_2WAY_MUL_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> + OTYPE, EXTRACT, EXTRACTD, INSERT, ELEMS, \
> + SCALE, OFFSET10, OFFSET11, OFFSET20, \
> + OFFSET21, OP, COMBINE) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET10)); \
> + E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET11)); \
> + E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET20)); \
> + E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET21)); \
> + DTYPE d = (DTYPE)EXTRACTD(dest, i); \
> + PTYPE prod0 = OP(s1_0, s2_0); \
> + PTYPE prod1 = OP(s1_1, s2_1); \
> + rd = INSERT(rd, (OTYPE)COMBINE(d, prod0, prod1), i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_4WAY_MUL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, OTYPE, \
> + EXTRACT, INSERT, ELEMS, SCALE, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + PTYPE prod0 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE)), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE))); \
> + PTYPE prod1 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 1), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE) + 1)); \
> + PTYPE prod2 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 2), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE) + 2)); \
> + PTYPE prod3 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 3), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE) + 3)); \
> + rd = INSERT(rd, (OTYPE)(prod0 + prod1 + prod2 + prod3), i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_4WAY_MUL_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> + OTYPE, EXTRACT, EXTRACTD, INSERT, ELEMS, \
> + SCALE, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + DTYPE d = (DTYPE)EXTRACTD(dest, i); \
> + PTYPE prod0 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE)), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE))); \
> + PTYPE prod1 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 1), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE) + 1)); \
> + PTYPE prod2 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 2), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE) + 2)); \
> + PTYPE prod3 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 3), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE) + 3)); \
> + rd = INSERT(rd, (OTYPE)(d + prod0 + prod1 + prod2 + prod3), i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_WIDEN_BINOP(NAME, ETYPE, WTYPE, OTYPE, ELEMS, IBITS, \
> + OBITS, IMASK, OP) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK)); \
> + ETYPE e2 = (ETYPE)((rs2 >> (i * (IBITS))) & (IMASK)); \
> + WTYPE res = OP((WTYPE)0, (WTYPE)e1, (WTYPE)e2); \
> + rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_WIDEN_BINOP_ACC(NAME, ETYPE, WTYPE, OTYPE, ELEMS, \
> + IBITS, OBITS, IMASK, OMASK, OP) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2, \
> + uint64_t dest) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK)); \
> + ETYPE e2 = (ETYPE)((rs2 >> (i * (IBITS))) & (IMASK)); \
> + WTYPE acc = (WTYPE)((dest >> (i * (OBITS))) & (OMASK)); \
> + WTYPE res = OP(acc, (WTYPE)e1, (WTYPE)e2); \
> + rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_WIDEN_MUL(NAME, E1TYPE, E2TYPE, PTYPE, OTYPE, ELEMS, \
> + EXTRACT, OBITS, OP) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i); \
> + PTYPE prod = OP(e1, e2); \
> + rd |= ((uint64_t)(OTYPE)prod) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_WIDEN_MUL_ACC(NAME, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> + OTYPE, ELEMS, EXTRACT, EXTRACTD, OBITS, \
> + OP) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2, \
> + uint64_t dest) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i); \
> + DTYPE d = (DTYPE)EXTRACTD(dest, i); \
> + PTYPE prod = OP(e1, e2); \
> + rd |= ((uint64_t)(OTYPE)(d + prod)) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_WIDEN_QMUL_ACC(NAME, ETYPE, DTYPE, PTYPE, STYPE, \
> + OTYPE, ELEMS, EXTRACT, EXTRACTD, SCALE, \
> + OFFSET, SHIFT, ROUND, OBITS, OP) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2, \
> + uint64_t dest) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET)); \
> + ETYPE e2 = (ETYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET)); \
> + DTYPE d = (DTYPE)EXTRACTD(dest, i); \
> + PTYPE prod = OP(e1, e2) + (ROUND); \
> + STYPE scaled = (STYPE)(((__int128_t)prod) >> (SHIFT)); \
> + rd |= ((uint64_t)(OTYPE)(d + scaled)) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_DW_2WAY_MUL(NAME, E1TYPE, E2TYPE, PTYPE, EXTRACT, \
> + OFFSET10, OFFSET11, OFFSET20, OFFSET21, \
> + OP, COMBINE) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2) \
> +{ \
> + E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, OFFSET10); \
> + E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, OFFSET11); \
> + E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, OFFSET20); \
> + E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, OFFSET21); \
> + PTYPE prod0 = OP(s1_0, s2_0); \
> + PTYPE prod1 = OP(s1_1, s2_1); \
> + \
> + return (uint64_t)COMBINE(0, prod0, prod1); \
> +}
> +
> +#define GEN_PSIMD_DW_2WAY_MUL_ACC(NAME, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> + EXTRACT, OFFSET10, OFFSET11, OFFSET20, \
> + OFFSET21, OP, COMBINE) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2, \
> + uint64_t dest) \
> +{ \
> + E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, OFFSET10); \
> + E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, OFFSET11); \
> + E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, OFFSET20); \
> + E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, OFFSET21); \
> + DTYPE d = (DTYPE)dest; \
> + PTYPE prod0 = OP(s1_0, s2_0); \
> + PTYPE prod1 = OP(s1_1, s2_1); \
> + \
> + return (uint64_t)COMBINE(d, prod0, prod1); \
> +}
> +
> +#define GEN_PSIMD_WIDEN_SHIFT(NAME, ETYPE, WTYPE, OTYPE, ELEMS, IBITS, \
> + OBITS, IMASK, SHMASK) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2) \
> +{ \
> + uint64_t rd = 0; \
> + uint8_t shamt = rs2 & (SHMASK); \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK)); \
> + WTYPE res = (WTYPE)e1 << shamt; \
> + rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_DW_ZIP(NAME, EXTRACT, ELEMS, STRIDE, BITS) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + uint64_t e1 = (uint64_t)EXTRACT(rs1, i) << ((STRIDE) * i); \
> + uint64_t e2 = (uint64_t)EXTRACT(rs2, i) \
> + << ((STRIDE) * i + (BITS)); \
> + rd |= e2 | e1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_DW_REDSUM(NAME, SUMTYPE, INITTYPE, ETYPE, EXTRACT, \
> + ELEMS) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1_lo, \
> + uint32_t rs1_hi, uint32_t rs2) \
> +{ \
> + SUMTYPE sum = (INITTYPE)rs2; \
> + uint64_t s1 = ((uint64_t)rs1_hi << 32) | rs1_lo; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + sum += (ETYPE)EXTRACT(s1, i); \
> + } \
> + return (uint32_t)sum; \
> +}
> +
> +#define GEN_PSIMD_NARROW_SRL(NAME, ETYPE, OTYPE, ELEMS, IBITS, OBITS, \
> + IMASK, SHMASK) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint32_t rd = 0; \
> + uint8_t shift = shamt & (SHMASK); \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
> + OTYPE result = (OTYPE)(e1 >> shift); \
> + rd |= ((uint32_t)result) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_NARROW_SRA_PACK(NAME, ETYPE, STYPE, OTYPE, ELEMS, \
> + IBITS, OBITS, IMASK, SHMASK) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint32_t rd = 0; \
> + uint8_t shift = shamt & (SHMASK); \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
> + STYPE shx = (STYPE)e1 >> shift; \
> + OTYPE result = (OTYPE)shx; \
> + rd |= ((uint32_t)result) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_NARROW_RNDSRA_PACK(NAME, ETYPE, STYPE, OTYPE, ELEMS, \
> + IBITS, OBITS, IMASK, SHMASK, RMASK) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint32_t rd = 0; \
> + uint8_t shift = shamt & (SHMASK); \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
> + STYPE e1_s = (STYPE)e1; \
> + uint64_t shx = (((uint64_t)e1_s << 1) >> shift) & (RMASK); \
> + OTYPE result = (OTYPE)((shx + 1) >> 1); \
> + rd |= ((uint32_t)result) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_NCLIP_SIGNED_PACK(NAME, ETYPE, STYPE, CTYPE, OTYPE, \
> + ELEMS, IBITS, OBITS, IMASK, SHMASK, \
> + MIN, MAX, MIN_RES, MAX_RES) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint32_t rd = 0; \
> + uint8_t shift = shamt & (SHMASK); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
> + CTYPE shx = (CTYPE)((STYPE)e1 >> shift); \
> + OTYPE result; \
> + \
> + if (shx < (MIN)) { \
> + sat = 1; \
> + result = (MIN_RES); \
> + } else if (shx > (MAX)) { \
> + sat = 1; \
> + result = (MAX_RES); \
> + } else { \
> + result = (OTYPE)shx; \
> + } \
> + rd |= ((uint32_t)result) << (i * (OBITS)); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_NCLIPR_SIGNED_PACK(NAME, ETYPE, STYPE, CTYPE, OTYPE, \
> + ELEMS, IBITS, OBITS, IMASK, SHMASK, \
> + RMASK, MIN, MAX, MIN_RES, MAX_RES) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint32_t rd = 0; \
> + uint8_t shift = shamt & (SHMASK); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
> + STYPE e1_s = (STYPE)e1; \
> + uint64_t shx = (((uint64_t)e1_s << 1) >> shift) & (RMASK); \
> + CTYPE round_shx = (CTYPE)((shx + 1) >> 1); \
> + OTYPE result; \
> + \
> + if (round_shx < (MIN)) { \
> + sat = 1; \
> + result = (MIN_RES); \
> + } else if (round_shx > (MAX)) { \
> + sat = 1; \
> + result = (MAX_RES); \
> + } else { \
> + result = (OTYPE)round_shx; \
> + } \
> + rd |= ((uint32_t)result) << (i * (OBITS)); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_NCLIP_UNSIGNED_PACK(NAME, ETYPE, WTYPE, OTYPE, ELEMS, \
> + IBITS, OBITS, IMASK, SHMASK, MAX) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint32_t rd = 0; \
> + uint8_t shift = shamt & (SHMASK); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
> + WTYPE shx = (WTYPE)e1 >> shift; \
> + OTYPE result; \
> + \
> + if (shx > (MAX)) { \
> + sat = 1; \
> + result = (OTYPE)(MAX); \
> + } else { \
> + result = (OTYPE)shx; \
> + } \
> + rd |= ((uint32_t)result) << (i * (OBITS)); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_NCLIPR_UNSIGNED_PACK(NAME, ETYPE, WTYPE, OTYPE, ELEMS, \
> + IBITS, OBITS, IMASK, SHMASK, MAX) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint32_t rd = 0; \
> + uint8_t shift = shamt & (SHMASK); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
> + WTYPE shx = ((WTYPE)e1 << 1) >> shift; \
> + WTYPE round_shx = (shx + 1) >> 1; \
> + OTYPE result; \
> + \
> + if (round_shx > (MAX)) { \
> + sat = 1; \
> + result = (OTYPE)(MAX); \
> + } else { \
> + result = (OTYPE)round_shx; \
> + } \
> + rd |= ((uint32_t)result) << (i * (OBITS)); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_NARROW_SRA(NAME) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + __int128_t s1_s128 = (__int128_t)((int64_t)s1); \
> + __int128_t s1_s96 = (s1_s128 << 32) >> 32; \
> + \
> + return (uint32_t)(s1_s96 >> (shamt & 0x3F)) & 0xFFFFFFFF; \
> +}
> +
> +#define GEN_PSIMD_NARROW_RNDSRA(NAME) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + __int128_t s1_s128 = (__int128_t)((int64_t)s1); \
> + __int128_t s1_s96 = (s1_s128 << 32) >> 32; \
> + __uint128_t shx_97bit = ((__uint128_t)s1_s96 << 1); \
> + uint64_t shx = (uint64_t)(shx_97bit >> (shamt & 0x3F)) & 0x1FFFFFFFF; \
> + \
> + return (uint32_t)((shx + 1) >> 1); \
> +}
> +
> +#define GEN_PSIMD_NARROW_ALIAS(NAME, TARGET) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + return HELPER(TARGET)(env, s1, shamt); \
> +}
> +
> +typedef struct {
> + __uint128_t low;
> + uint8_t high;
> +} PsImdUint129;
> +
> +static inline PsImdUint129 psimd_uint129_lshift1(__int128_t val)
> +{
> + PsImdUint129 result;
> + __uint128_t uval = (__uint128_t)val;
> +
> + result.low = uval << 1;
> + result.high = (uval >> 127) & 0x1;
> + return result;
> +}
> +
> +static inline PsImdUint129 psimd_uint129_rshift(PsImdUint129 val,
> + uint32_t shamt)
> +{
> + PsImdUint129 result;
> +
> + if (shamt == 0) {
> + return val;
> + } else if (shamt >= 129) {
> + result.low = 0;
> + result.high = 0;
> + } else if (shamt == 128) {
> + result.low = val.high;
> + result.high = 0;
> + } else {
> + result.low = (val.low >> shamt) |
> + ((__uint128_t)val.high << (128 - shamt));
> + result.high = val.high >> shamt;
> + }
> + return result;
> +}
> +
> +#define GEN_PSIMD_NCLIP(NAME) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + __int128_t s1_s128 = (__int128_t)((int64_t)s1); \
> + int64_t shx = (int64_t)(s1_s128 >> (shamt & 0x3F)); \
> + \
> + if (shx < -2147483648LL) { \
> + env->vxsat = 1; \
> + return 0x80000000U; \
> + } else if (shx > 2147483647LL) { \
> + env->vxsat = 1; \
> + return 0x7FFFFFFFU; \
> + } else { \
> + return (uint32_t)(shx & 0xFFFFFFFF); \
> + } \
> +}
> +
> +#define GEN_PSIMD_NCLIPR(NAME) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + __int128_t s1_s128 = (__int128_t)((int64_t)s1); \
> + PsImdUint129 shx_129bit = psimd_uint129_lshift1(s1_s128); \
> + PsImdUint129 shx = psimd_uint129_rshift(shx_129bit, shamt & 0x3F); \
> + int64_t round_shx = (int64_t)((shx.low + 1) >> 1); \
> + \
> + if (round_shx < -2147483648LL) { \
> + env->vxsat = 1; \
> + return 0x80000000U; \
> + } else if (round_shx > 2147483647LL) { \
> + env->vxsat = 1; \
> + return 0x7FFFFFFFU; \
> + } else { \
> + return (uint32_t)round_shx; \
> + } \
> +}
> +
> +#define GEN_PSIMD_NCLIPU(NAME) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint64_t shx = s1 >> (shamt & 0x3F); \
> + \
> + if (shx > 4294967295ULL) { \
> + env->vxsat = 1; \
> + return 0xFFFFFFFFU; \
> + } else { \
> + return (uint32_t)(shx & 0xFFFFFFFF); \
> + } \
> +}
> +
> +#define GEN_PSIMD_NCLIPRU(NAME) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + __uint128_t shx_65bit = (__uint128_t)s1 << 1; \
> + __uint128_t shx = shx_65bit >> (shamt & 0x3F); \
> + uint64_t round_shx = (shx + 1) >> 1; \
> + \
> + if (round_shx > 4294967295ULL) { \
> + env->vxsat = 1; \
> + return 0xFFFFFFFFU; \
> + } else { \
> + return (uint32_t)(round_shx & 0xFFFFFFFF); \
> + } \
> +}
> +
> +/* Basic addition operations (non-saturating) */
> +
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework
2026-07-17 10:06 ` [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework Molly Chen
2026-07-26 19:53 ` Daniel Henrique Barboza
@ 2026-07-27 6:16 ` Nutty.Liu
2026-07-29 9:01 ` Chao Liu
2 siblings, 0 replies; 31+ messages in thread
From: Nutty.Liu @ 2026-07-27 6:16 UTC (permalink / raw)
To: Molly Chen, palmer, alistair.francis, liwei1518, daniel.barboza,
zhiwei_liu, chao.liu.zevorn, Chao Liu
Cc: qemu-riscv, qemu-devel
On 7/17/2026 6:06 PM, Molly Chen wrote:
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
It would be better to add some description for this series.
Otherwise,
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Thanks,
Nutty
> ---
> target/riscv/tcg/meson.build | 3 +-
> target/riscv/tcg/psimd_helper.c | 1656 +++++++++++++++++++++++++++++++
> 2 files changed, 1658 insertions(+), 1 deletion(-)
> create mode 100644 target/riscv/tcg/psimd_helper.c
>
> diff --git a/target/riscv/tcg/meson.build b/target/riscv/tcg/meson.build
> index a05ab642f41..cc438d7c0d2 100644
> --- a/target/riscv/tcg/meson.build
> +++ b/target/riscv/tcg/meson.build
> @@ -15,7 +15,8 @@ riscv_ss.add(files(
> 'vcrypto_helper.c',
> 'vector_helper.c',
> 'vector_internals.c',
> - 'zce_helper.c'))
> + 'zce_helper.c',
> + 'psimd_helper.c'))
>
>
> riscv_system_ss.add(files(
> diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
> new file mode 100644
> index 00000000000..2948bbb2a86
> --- /dev/null
> +++ b/target/riscv/tcg/psimd_helper.c
> @@ -0,0 +1,1656 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/* RISC-V Packed SIMD Extension Helpers for QEMU. */
> +/* Copyright (C) 2026 ISRC ISCAS. */
> +
> +#include "qemu/osdep.h"
> +#include "cpu.h"
> +#include "qemu/host-utils.h"
> +#include "exec/helper-proto.h"
> +#include "fpu/softfloat.h"
> +#include "internals.h"
> +
> +
> +/* Helper macros */
> +
> +/* Element count calculations */
> +#define ELEMS_B(target) (sizeof(target) * 8 / 8) /* byte elements count */
> +#define ELEMS_H(target) (sizeof(target) * 8 / 16)
> +#define ELEMS_W(target) (sizeof(target) * 8 / 32) /* word elements count */
> +#define ELEMS_D(target) (sizeof(target) * 8 / 64)
> +
> +/* Element extraction macros - unsigned to avoid sign extension */
> +#define EXTRACT8(val, idx) (((val) >> ((idx) * 8)) & 0xFF)
> +#define EXTRACT16(val, idx) (((val) >> ((idx) * 16)) & 0xFFFF)
> +#define EXTRACT32(val, idx) (((val) >> ((idx) * 32)) & 0xFFFFFFFF)
> +#define EXTRACT64(val, idx) (((val) >> ((idx) * 64)) & 0xFFFFFFFFFFFFFFFFULL)
> +
> +/* Element insertion macros */
> +#define INSERT8(val, res, idx) \
> + ((val) | ((target_ulong)(uint8_t)(res) << ((idx) * 8)))
> +#define INSERT16(val, res, idx) \
> + ((val) | ((target_ulong)(uint16_t)(res) << ((idx) * 16)))
> +#define INSERT32(val, res, idx) \
> + ((val) | ((target_ulong)(uint32_t)(res) << ((idx) * 32)))
> +#define INSERT32_64(val, res, idx) \
> + ((val) | ((uint64_t)(uint32_t)(res) << ((idx) * 32)))
> +#define INSERT64(val, res, idx) \
> + ((val) | ((uint64_t)(res) << ((idx) * 64)))
> +
> +/* Saturation constants */
> +static const int8_t SAT_MAX_B = 127;
> +static const int8_t SAT_MIN_B = -128;
> +static const int16_t SAT_MAX_H = 32767;
> +static const int16_t SAT_MIN_H = -32768;
> +static const int32_t SAT_MAX_W = 2147483647;
> +static const int32_t SAT_MIN_W = -2147483648LL;
> +static const uint8_t USAT_MAX_B = 255;
> +static const uint16_t USAT_MAX_H = 65535;
> +static const uint32_t USAT_MAX_W = 4294967295U;
> +
> +
> +/* Saturation helper functions */
> +
> +/**
> + * Signed saturation for 8-bit elements
> + * Returns saturated value and sets *sat if saturation occurred
> + */
> +static inline int8_t signed_saturate_b(int32_t val, int *sat)
> +{
> + if (val > SAT_MAX_B) {
> + *sat = 1;
> + return SAT_MAX_B;
> + }
> + if (val < SAT_MIN_B) {
> + *sat = 1;
> + return SAT_MIN_B;
> + }
> + return (int8_t)val;
> +}
> +
> +/**
> + * Signed saturation for 16-bit elements
> + */
> +static inline int16_t signed_saturate_h(int32_t val, int *sat)
> +{
> + if (val > SAT_MAX_H) {
> + *sat = 1;
> + return SAT_MAX_H;
> + }
> + if (val < SAT_MIN_H) {
> + *sat = 1;
> + return SAT_MIN_H;
> + }
> + return (int16_t)val;
> +}
> +
> +/**
> + * Signed saturation for 32-bit elements
> + */
> +static inline int32_t signed_saturate_w(int64_t val, int *sat)
> +{
> + if (val > SAT_MAX_W) {
> + *sat = 1;
> + return SAT_MAX_W;
> + }
> + if (val < SAT_MIN_W) {
> + *sat = 1;
> + return SAT_MIN_W;
> + }
> + return (int32_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 8-bit elements
> + */
> +static inline uint8_t unsigned_saturate_b(uint32_t val, int *sat)
> +{
> + if (val > USAT_MAX_B) {
> + *sat = 1;
> + return USAT_MAX_B;
> + }
> + return (uint8_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 16-bit elements
> + */
> +static inline uint16_t unsigned_saturate_h(uint32_t val, int *sat)
> +{
> + if (val > USAT_MAX_H) {
> + *sat = 1;
> + return USAT_MAX_H;
> + }
> + return (uint16_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 32-bit elements
> + */
> +static inline uint32_t unsigned_saturate_w(uint64_t val, int *sat)
> +{
> + if (val > USAT_MAX_W) {
> + *sat = 1;
> + return USAT_MAX_W;
> + }
> + return (uint32_t)val;
> +}
> +
> +static inline target_ulong psimd_abdsumu_b(target_ulong rs1,
> + target_ulong rs2,
> + target_ulong sum)
> +{
> + int elems = ELEMS_B(rs1);
> +
> + for (int i = 0; i < elems; i++) {
> + uint8_t e1 = EXTRACT8(rs1, i);
> + uint8_t e2 = EXTRACT8(rs2, i);
> + uint8_t diff = (e1 > e2) ? (e1 - e2) : (e2 - e1);
> + sum += diff;
> + }
> +
> + return sum;
> +}
> +
> +#define PSIMD_DO_ADD(N, M) ((N) + (M))
> +#define PSIMD_DO_SUB(N, M) ((N) - (M))
> +#define PSIMD_DO_ABD(N, M) ((N) >= (M) ? (N) - (M) : (M) - (N))
> +#define PSIMD_DO_EQ_MASK(N, M) ((N) == (M) ? -1 : 0)
> +#define PSIMD_DO_LT_MASK(N, M) ((N) < (M) ? -1 : 0)
> +#define PSIMD_DO_MIN(N, M) ((N) < (M) ? (N) : (M))
> +#define PSIMD_DO_MAX(N, M) ((N) > (M) ? (N) : (M))
> +#define PSIMD_DO_SLL(N, M) ((N) << (M))
> +#define PSIMD_DO_SRL(N, M) ((N) >> (M))
> +#define PSIMD_DO_SRA(N, M) ((N) >> (M))
> +
> +#define GEN_PSIMD_BINOP(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT, \
> + ELEMS, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + STYPE e1 = (STYPE)EXTRACT(rs1, i); \
> + STYPE e2 = (STYPE)EXTRACT(rs2, i); \
> + DTYPE res = (DTYPE)OP(e1, e2); \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_BINOP_SCALAR(NAME, RTYPE, ETYPE, EXTRACT, INSERT, \
> + ELEMS, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + ETYPE e2 = (ETYPE)EXTRACT(rs2, 0); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res = OP(e1, e2); \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_SHIFTOP(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT, \
> + ELEMS, SHMASK, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + uint8_t shamt = rs2 & (SHMASK); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + STYPE e1 = (STYPE)EXTRACT(rs1, i); \
> + DTYPE res = (DTYPE)OP(e1, shamt); \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_SAT_SHIFTOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, SHMASK, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + uint8_t shamt = rs2 & (SHMASK); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + WTYPE shifted = (WTYPE)e1 << shamt; \
> + ETYPE res = SAT_FN(shifted, &sat); \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_ROUND_SRAI(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, SHMASK) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + uint8_t shamt = rs2 & (SHMASK); \
> + \
> + if (shamt == 0) { \
> + return rs1; \
> + } \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + WTYPE rounded = (((WTYPE)e1 >> (shamt - 1)) + 1) >> 1; \
> + rd = INSERT(rd, (ETYPE)rounded, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_SAT_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, OP, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE e2 = (ETYPE)EXTRACT(rs2, i); \
> + WTYPE val = OP((WTYPE)e1, (WTYPE)e2); \
> + ETYPE res = SAT_FN(val, &sat); \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_USUB_SAT(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE e2 = (ETYPE)EXTRACT(rs2, i); \
> + ETYPE res = (e1 >= e2) ? (e1 - e2) : 0; \
> + if (e1 < e2) { \
> + sat = 1; \
> + } \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_AVG_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + WTYPE e1 = (WTYPE)(ETYPE)EXTRACT(rs1, i); \
> + WTYPE e2 = (WTYPE)(ETYPE)EXTRACT(rs2, i); \
> + ETYPE res = (ETYPE)(OP(e1, e2) >> 1); \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_SHADD(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS, \
> + SHAMT) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE e2 = (ETYPE)EXTRACT(rs2, i); \
> + ETYPE res = (e1 << (SHAMT)) + e2; \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_SAT_SHADD(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, SHAMT, SH_MIN, SH_MAX, SAT_MIN, \
> + SAT_MAX, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE e2 = (ETYPE)EXTRACT(rs2, i); \
> + WTYPE shifted; \
> + \
> + if (e1 > (SH_MAX) || e1 < (SH_MIN)) { \
> + shifted = (e1 < 0) ? (SAT_MIN) : (SAT_MAX); \
> + sat = 1; \
> + } else { \
> + shifted = (WTYPE)e1 << (SHAMT); \
> + } \
> + \
> + WTYPE sum = shifted + e2; \
> + ETYPE res = SAT_FN(sum, &sat); \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_SATI(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, IMMMASK) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE imm) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int range = (imm & (IMMMASK)) + 1; \
> + WTYPE max = ((WTYPE)1 << (range - 1)) - 1; \
> + WTYPE min = -((WTYPE)1 << (range - 1)); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res; \
> + \
> + if (e1 > max) { \
> + res = max; \
> + sat = 1; \
> + } else if (e1 < min) { \
> + res = min; \
> + sat = 1; \
> + } else { \
> + res = e1; \
> + } \
> + \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_USATI(NAME, RTYPE, ETYPE, UTYPE, WTYPE, EXTRACT, \
> + INSERT, ELEMS, ONE) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE imm) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + WTYPE max = ((WTYPE)(ONE) << imm) - 1; \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res; \
> + \
> + if (e1 < 0) { \
> + res = 0; \
> + sat = 1; \
> + } else if ((UTYPE)e1 > max) { \
> + res = max; \
> + sat = 1; \
> + } else { \
> + res = e1; \
> + } \
> + \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_ABS(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS, \
> + MINVAL, MAXVAL) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res; \
> + \
> + if (e1 == (MINVAL)) { \
> + res = (MAXVAL); \
> + sat = 1; \
> + } else if (e1 < 0) { \
> + res = -e1; \
> + } else { \
> + res = e1; \
> + } \
> + \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_SCALAR_ABS(NAME, RTYPE, STYPE, UTYPE) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1) \
> +{ \
> + STYPE value = (STYPE)rs1; \
> + UTYPE result = (UTYPE)value; \
> + \
> + if (value < 0) { \
> + result = (UTYPE)0 - result; \
> + } \
> + return (RTYPE)(STYPE)result; \
> +}
> +
> +#define GEN_PSIMD_VAR_SSHA(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, BITS, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + int8_t shamt = (int8_t)(rs2 & 0xff); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res; \
> + \
> + if (shamt >= 0) { \
> + WTYPE shifted = (WTYPE)e1 << shamt; \
> + res = SAT_FN(shifted, &sat); \
> + } else { \
> + int right = -shamt; \
> + if (right >= (BITS)) { \
> + res = (e1 < 0) ? -1 : 0; \
> + } else { \
> + res = e1 >> right; \
> + } \
> + } \
> + \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_VAR_SSHAR(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, BITS, SAT_MIN, SAT_MAX, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + int8_t shamt = (int8_t)(rs2 & 0xff); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res; \
> + \
> + if (shamt >= 0) { \
> + if (shamt >= (BITS)) { \
> + if (e1 == 0) { \
> + res = 0; \
> + } else if (e1 > 0) { \
> + res = (SAT_MAX); \
> + sat = 1; \
> + } else { \
> + res = (SAT_MIN); \
> + sat = 1; \
> + } \
> + } else { \
> + WTYPE shifted = (WTYPE)e1 * ((WTYPE)1 << shamt); \
> + res = SAT_FN(shifted, &sat); \
> + } \
> + } else { \
> + int right = -shamt; \
> + if (right >= (BITS)) { \
> + res = 0; \
> + } else { \
> + WTYPE rounded = ((e1 >> (right - 1)) + 1) >> 1; \
> + res = (ETYPE)rounded; \
> + } \
> + } \
> + \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_VAR_USHL(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, BITS, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + int8_t shamt = (int8_t)(rs2 & 0xff); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res; \
> + \
> + if (shamt >= 0) { \
> + WTYPE shifted = (shamt >= (BITS)) ? \
> + ((WTYPE)e1 << (BITS)) : \
> + ((WTYPE)e1 << shamt); \
> + res = SAT_FN(shifted, &sat); \
> + } else { \
> + int right = -shamt; \
> + if (right >= (BITS)) { \
> + res = 0; \
> + } else { \
> + res = e1 >> right; \
> + } \
> + } \
> + \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_VAR_USHLR(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, INSERT, \
> + ELEMS, BITS, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + int8_t shamt = (int8_t)(rs2 & 0xff); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE res; \
> + \
> + if (shamt >= 0) { \
> + WTYPE shifted = (shamt >= (BITS)) ? \
> + ((WTYPE)e1 << (BITS)) : \
> + ((WTYPE)e1 << shamt); \
> + res = SAT_FN(shifted, &sat); \
> + } else { \
> + int right = -shamt; \
> + if (right > (BITS)) { \
> + res = 0; \
> + } else { \
> + WTYPE rounded = ((WTYPE)e1 >> (right - 1)) + 1; \
> + res = (ETYPE)(rounded >> 1); \
> + } \
> + } \
> + \
> + rd = INSERT(rd, res, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define PSIMD_DO_SRA64(A, B) ((A) >> (B))
> +#define PSIMD_DO_RNDSRA64(A, B) \
> + ((int64_t)((((__int128_t)(A) >> ((B) - 1)) + 1) >> 1))
> +
> +#define GEN_PSIMD_VAR_SRA64(NAME, RIGHT_OP) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
> +{ \
> + int64_t a = (int64_t)rs1; \
> + int8_t shamt = (int8_t)(rs2 & 0xff); \
> + \
> + if (shamt >= 0) { \
> + return (uint64_t)(a << shamt); \
> + } \
> + \
> + int right = -shamt; \
> + if (right >= 64) { \
> + return (a < 0) ? (uint64_t)-1 : 0; \
> + } \
> + return (uint64_t)RIGHT_OP(a, right); \
> +}
> +
> +#define PSIMD_DO_SRL64(A, B) (((B) >= 64) ? 0 : ((A) >> (B)))
> +#define PSIMD_DO_RNDSRL64(A, B) \
> + (((B) > 64) ? 0 : ((((A) >> ((B) - 1)) + 1) >> 1))
> +
> +#define GEN_PSIMD_VAR_SRL64(NAME, RIGHT_OP) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
> +{ \
> + int8_t shamt = (int8_t)(rs2 & 0xff); \
> + \
> + if (shamt < 0) { \
> + return RIGHT_OP(rs1, -shamt); \
> + } \
> + return (shamt >= 64) ? 0 : (rs1 << shamt); \
> +}
> +
> +#define GEN_PSIMD_XPAIR_BINOP(NAME, RTYPE, ETYPE, EXTRACT, INSERT, \
> + ELEMS, OP_LO, OP_HI) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i += 2) { \
> + ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1); \
> + ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i); \
> + ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1); \
> + ETYPE res_lo = OP_LO(s1_lo, s2_hi); \
> + ETYPE res_hi = OP_HI(s1_hi, s2_lo); \
> + rd = INSERT(rd, res_lo, i); \
> + rd = INSERT(rd, res_hi, i + 1); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_XPAIR_SAT_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, \
> + INSERT, ELEMS, OP_LO, OP_HI, SAT_FN) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i += 2) { \
> + ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1); \
> + ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i); \
> + ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1); \
> + WTYPE val_lo = OP_LO((WTYPE)s1_lo, (WTYPE)s2_hi); \
> + WTYPE val_hi = OP_HI((WTYPE)s1_hi, (WTYPE)s2_lo); \
> + ETYPE res_lo = SAT_FN(val_lo, &sat); \
> + ETYPE res_hi = SAT_FN(val_hi, &sat); \
> + rd = INSERT(rd, res_lo, i); \
> + rd = INSERT(rd, res_hi, i + 1); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_XPAIR_AVG_BINOP(NAME, RTYPE, ETYPE, WTYPE, EXTRACT, \
> + INSERT, ELEMS, OP_LO, OP_HI) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i += 2) { \
> + ETYPE s1_lo = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE s1_hi = (ETYPE)EXTRACT(rs1, i + 1); \
> + ETYPE s2_lo = (ETYPE)EXTRACT(rs2, i); \
> + ETYPE s2_hi = (ETYPE)EXTRACT(rs2, i + 1); \
> + ETYPE res_lo = (ETYPE)(OP_LO((WTYPE)s1_lo, (WTYPE)s2_hi) >> 1); \
> + ETYPE res_hi = (ETYPE)(OP_HI((WTYPE)s1_hi, (WTYPE)s2_lo) >> 1); \
> + rd = INSERT(rd, res_lo, i); \
> + rd = INSERT(rd, res_hi, i + 1); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_REDSUM(NAME, RTYPE, SUMTYPE, ETYPE, EXTRACT, ELEMS, \
> + INIT) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + SUMTYPE sum = (INIT); \
> + int elems = ELEMS(rs1); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + sum += e1; \
> + } \
> + \
> + return (RTYPE)sum; \
> +}
> +
> +#define PSIMD_PAIR_LO(V, MASK, SHIFT) ((V) & (MASK))
> +#define PSIMD_PAIR_HI(V, MASK, SHIFT) (((V) >> (SHIFT)) & (MASK))
> +
> +#define GEN_PSIMD_PAIR_PACK(NAME, RTYPE, ETYPE, EXTRACT, INSERT, ELEMS, \
> + MASK, SHIFT, HI_SEL, LO_SEL) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = EXTRACT(rs1, i); \
> + ETYPE e2 = EXTRACT(rs2, i); \
> + ETYPE res = (HI_SEL(e2, MASK, SHIFT) << (SHIFT)) | \
> + LO_SEL(e1, MASK, SHIFT); \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_PAIR_WORD(NAME, RS1_IDX, RS2_IDX) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
> +{ \
> + uint32_t e1 = EXTRACT32(rs1, RS1_IDX); \
> + uint32_t e2 = EXTRACT32(rs2, RS2_IDX); \
> + \
> + return ((uint64_t)e2 << 32) | e1; \
> +}
> +
> +#define GEN_PSIMD_SIGN_EXTEND(NAME, RTYPE, STYPE, DTYPE, EXTRACT, INSERT, \
> + ELEMS, SCALE) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + STYPE e1 = (STYPE)EXTRACT(rs1, i * (SCALE)); \
> + rd = INSERT(rd, (DTYPE)e1, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_ZIP(NAME, ETYPE, EXTRACT, ELEMS, BITS, START) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = EXTRACT(rs1, (START) - i); \
> + ETYPE e2 = EXTRACT(rs2, (START) - i); \
> + rd = (rd << (2 * (BITS))) | ((uint64_t)e2 << (BITS)) | e1; \
> + } \
> + \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_UNZIP(NAME, EXTRACT, ELEMS, BITS, OFFSET) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + uint64_t e1 = (uint64_t)EXTRACT(rs1, 2 * i + (OFFSET)) << \
> + ((BITS) * i); \
> + uint64_t e2 = (uint64_t)EXTRACT(rs2, 2 * i + (OFFSET)) << \
> + (32 + (BITS) * i); \
> + rd = rd | e2 | e1; \
> + } \
> + \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_BIT_SELECT(NAME, MASK, TRUE_VAL, FALSE_VAL) \
> +target_ulong HELPER(NAME)(CPURISCVState *env, target_ulong rs1, \
> + target_ulong rs2, target_ulong rd) \
> +{ \
> + return (~(MASK) & (FALSE_VAL)) | ((MASK) & (TRUE_VAL)); \
> +}
> +
> +#define GEN_PSIMD_NCLIP_PACK(NAME, ITYPE, OTYPE, EXTRACT, INSERT, ELEMS, \
> + SAT_FN) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
> +{ \
> + uint64_t rd = 0; \
> + int sat = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ITYPE lo = (ITYPE)EXTRACT(rs1, i); \
> + ITYPE hi = (ITYPE)EXTRACT(rs2, i); \
> + OTYPE res_lo = SAT_FN(lo, &sat); \
> + OTYPE res_hi = SAT_FN(hi, &sat); \
> + \
> + rd = (uint64_t)INSERT(rd, res_lo, i); \
> + rd = (uint64_t)INSERT(rd, res_hi, i + (ELEMS)); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_CLS(NAME, RTYPE, UTYPE, CLRSB) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1) \
> +{ \
> + return CLRSB((UTYPE)rs1); \
> +}
> +
> +#define PSIMD_MUL_S32(A, B) ((int32_t)(A) * (int32_t)(B))
> +#define PSIMD_MUL_SU16(A, B) ((int16_t)(A) * (uint16_t)(B))
> +#define PSIMD_MUL_SU32(A, B) ((int32_t)(A) * (uint32_t)(B))
> +#define PSIMD_MUL_U32(A, B) ((uint32_t)(A) * (uint32_t)(B))
> +#define PSIMD_MUL_S64(A, B) ((int64_t)(A) * (int64_t)(B))
> +#define PSIMD_MUL_SU64(A, B) ((int64_t)(A) * (uint64_t)(B))
> +#define PSIMD_MUL_U64(A, B) ((uint64_t)(A) * (uint64_t)(B))
> +
> +#define GEN_PSIMD_MUL_HIGH(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, HTYPE, \
> + EXTRACT, INSERT, ELEMS, SHIFT, ROUND, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i); \
> + PTYPE prod = OP(e1, e2) + (ROUND); \
> + HTYPE high = (HTYPE)(prod >> (SHIFT)); \
> + rd = INSERT(rd, high, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_MUL_HIGH_SEL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, \
> + HTYPE, EXTRACT1, EXTRACT2, INSERT, ELEMS, \
> + SCALE, OFFSET, SHIFT, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT1(rs1, i); \
> + E2TYPE e2 = (E2TYPE)EXTRACT2(rs2, i * (SCALE) + (OFFSET)); \
> + PTYPE prod = OP(e1, e2); \
> + HTYPE high = (HTYPE)(prod >> (SHIFT)); \
> + rd = INSERT(rd, high, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_MUL_ELEM_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, \
> + OTYPE, EXTRACT, INSERT, ELEMS, SCALE, \
> + OFFSET1, OFFSET2, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1)); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2)); \
> + PTYPE mul = OP(e1, e2); \
> + rd = INSERT(rd, (OTYPE)mul, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_MUL_ELEM_SCALAR(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, \
> + EXTRACT, OFFSET1, OFFSET2, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, OFFSET1); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, OFFSET2); \
> + PTYPE mul = OP(e1, e2); \
> + \
> + return (RTYPE)mul; \
> +}
> +
> +#define GEN_PSIMD_MUL_HIGH_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> + HTYPE, OTYPE, EXTRACT, INSERT, ELEMS, \
> + SHIFT, ROUND, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i); \
> + DTYPE d = (DTYPE)EXTRACT(dest, i); \
> + PTYPE prod = OP(e1, e2) + (ROUND); \
> + HTYPE high = (HTYPE)(prod >> (SHIFT)); \
> + OTYPE res = (OTYPE)(high + d); \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_MUL_HIGH_ACC_SEL(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, \
> + PTYPE, HTYPE, OTYPE, EXTRACT1, \
> + EXTRACT2, INSERT, ELEMS, SCALE, \
> + OFFSET, SHIFT, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT1(rs1, i); \
> + E2TYPE e2 = (E2TYPE)EXTRACT2(rs2, i * (SCALE) + (OFFSET)); \
> + DTYPE d = (DTYPE)EXTRACT1(dest, i); \
> + PTYPE prod = OP(e1, e2); \
> + HTYPE high = (HTYPE)(prod >> (SHIFT)); \
> + OTYPE res = (OTYPE)(high + d); \
> + rd = INSERT(rd, res, i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_MUL_ACC_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, \
> + PTYPE, OTYPE, EXTRACT, EXTRACTD, \
> + INSERT, ELEMS, SCALE, OFFSET1, \
> + OFFSET2, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1)); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2)); \
> + DTYPE d = (DTYPE)EXTRACTD(dest, i); \
> + PTYPE mul = OP(e1, e2); \
> + rd = INSERT(rd, (OTYPE)(d + mul), i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_QMUL(NAME, RTYPE, ETYPE, PTYPE, OTYPE, EXTRACT, INSERT, \
> + ELEMS, SHIFT, ROUND, MINVAL, MAXVAL) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i); \
> + ETYPE e2 = (ETYPE)EXTRACT(rs2, i); \
> + OTYPE result; \
> + \
> + if ((e1 == (ETYPE)(MINVAL)) && (e2 == (ETYPE)(MINVAL))) { \
> + sat = 1; \
> + result = (OTYPE)(MAXVAL); \
> + } else { \
> + PTYPE prod = (PTYPE)e1 * (PTYPE)e2 + (ROUND); \
> + result = (OTYPE)(prod >> (SHIFT)); \
> + } \
> + rd = INSERT(rd, result, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_QMUL_ACC_INDEXED(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, \
> + PTYPE, STYPE, OTYPE, EXTRACT, \
> + EXTRACTD, INSERT, ELEMS, SCALE, \
> + OFFSET1, OFFSET2, SHIFT, ROUND, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET1)); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET2)); \
> + DTYPE d = (DTYPE)EXTRACTD(dest, i); \
> + PTYPE prod = OP(e1, e2) + (ROUND); \
> + STYPE scaled = (STYPE)(((__int128_t)prod) >> (SHIFT)); \
> + rd = INSERT(rd, (OTYPE)(d + scaled), i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_Q2ADD(NAME, RTYPE, ETYPE, PTYPE, STYPE, OTYPE, EXTRACT, \
> + INSERT, ELEMS, SCALE, SHIFT, ROUND, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE s1_0 = (ETYPE)EXTRACT(rs1, i * (SCALE)); \
> + ETYPE s1_1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + 1); \
> + ETYPE s2_0 = (ETYPE)EXTRACT(rs2, i * (SCALE)); \
> + ETYPE s2_1 = (ETYPE)EXTRACT(rs2, i * (SCALE) + 1); \
> + PTYPE prod0 = OP(s1_0, s2_0) + (ROUND); \
> + PTYPE prod1 = OP(s1_1, s2_1) + (ROUND); \
> + STYPE scaled0 = (STYPE)(((__int128_t)prod0) >> (SHIFT)); \
> + STYPE scaled1 = (STYPE)(((__int128_t)prod1) >> (SHIFT)); \
> + rd = INSERT(rd, (OTYPE)(scaled0 + scaled1), i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_Q2ADDA(NAME, RTYPE, ETYPE, DTYPE, PTYPE, STYPE, OTYPE, \
> + EXTRACT, EXTRACTD, INSERT, ELEMS, SCALE, \
> + SHIFT, ROUND, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + ETYPE s1_0 = (ETYPE)EXTRACT(rs1, i * (SCALE)); \
> + ETYPE s1_1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + 1); \
> + ETYPE s2_0 = (ETYPE)EXTRACT(rs2, i * (SCALE)); \
> + ETYPE s2_1 = (ETYPE)EXTRACT(rs2, i * (SCALE) + 1); \
> + DTYPE d = (DTYPE)EXTRACTD(dest, i); \
> + PTYPE prod0 = OP(s1_0, s2_0) + (ROUND); \
> + PTYPE prod1 = OP(s1_1, s2_1) + (ROUND); \
> + STYPE scaled0 = (STYPE)(((__int128_t)prod0) >> (SHIFT)); \
> + STYPE scaled1 = (STYPE)(((__int128_t)prod1) >> (SHIFT)); \
> + rd = INSERT(rd, (OTYPE)(d + scaled0 + scaled1), i); \
> + } \
> + return rd; \
> +}
> +
> +#define PSIMD_COMB_ADD(D, A, B) ((D) + (A) + (B))
> +#define PSIMD_COMB_SUB(D, A, B) ((D) + (A) - (B))
> +
> +#define GEN_PSIMD_2WAY_MUL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, OTYPE, \
> + EXTRACT, INSERT, ELEMS, SCALE, OFFSET10, \
> + OFFSET11, OFFSET20, OFFSET21, OP, COMBINE) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET10)); \
> + E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET11)); \
> + E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET20)); \
> + E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET21)); \
> + PTYPE prod0 = OP(s1_0, s2_0); \
> + PTYPE prod1 = OP(s1_1, s2_1); \
> + rd = INSERT(rd, (OTYPE)COMBINE(0, prod0, prod1), i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_2WAY_SAT_MUL(NAME, OFFSET10, OFFSET11, OFFSET20, \
> + OFFSET21) \
> +target_ulong HELPER(NAME)(CPURISCVState *env, target_ulong rs1, \
> + target_ulong rs2) \
> +{ \
> + target_ulong rd = 0; \
> + int sat = 0; \
> + \
> + for (int i = 0; i < ELEMS_W(rd); i++) { \
> + int16_t s1_0 = (int16_t)EXTRACT16(rs1, i * 2 + (OFFSET10)); \
> + int16_t s1_1 = (int16_t)EXTRACT16(rs1, i * 2 + (OFFSET11)); \
> + int16_t s2_0 = (int16_t)EXTRACT16(rs2, i * 2 + (OFFSET20)); \
> + int16_t s2_1 = (int16_t)EXTRACT16(rs2, i * 2 + (OFFSET21)); \
> + uint32_t result; \
> + \
> + if (s1_0 == INT16_MIN && s1_1 == INT16_MIN && \
> + s2_0 == INT16_MIN && s2_1 == INT16_MIN) { \
> + result = INT32_MAX; \
> + sat = 1; \
> + } else { \
> + int32_t prod0 = (int32_t)s1_0 * s2_0; \
> + int32_t prod1 = (int32_t)s1_1 * s2_1; \
> + result = (uint32_t)(prod0 + prod1); \
> + } \
> + rd = INSERT32(rd, result, i); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_2WAY_MUL_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> + OTYPE, EXTRACT, EXTRACTD, INSERT, ELEMS, \
> + SCALE, OFFSET10, OFFSET11, OFFSET20, \
> + OFFSET21, OP, COMBINE) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET10)); \
> + E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET11)); \
> + E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET20)); \
> + E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET21)); \
> + DTYPE d = (DTYPE)EXTRACTD(dest, i); \
> + PTYPE prod0 = OP(s1_0, s2_0); \
> + PTYPE prod1 = OP(s1_1, s2_1); \
> + rd = INSERT(rd, (OTYPE)COMBINE(d, prod0, prod1), i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_4WAY_MUL(NAME, RTYPE, E1TYPE, E2TYPE, PTYPE, OTYPE, \
> + EXTRACT, INSERT, ELEMS, SCALE, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + PTYPE prod0 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE)), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE))); \
> + PTYPE prod1 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 1), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE) + 1)); \
> + PTYPE prod2 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 2), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE) + 2)); \
> + PTYPE prod3 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 3), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE) + 3)); \
> + rd = INSERT(rd, (OTYPE)(prod0 + prod1 + prod2 + prod3), i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_4WAY_MUL_ACC(NAME, RTYPE, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> + OTYPE, EXTRACT, EXTRACTD, INSERT, ELEMS, \
> + SCALE, OP) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1, RTYPE rs2, RTYPE dest) \
> +{ \
> + RTYPE rd = 0; \
> + int elems = ELEMS(rd); \
> + \
> + for (int i = 0; i < elems; i++) { \
> + DTYPE d = (DTYPE)EXTRACTD(dest, i); \
> + PTYPE prod0 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE)), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE))); \
> + PTYPE prod1 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 1), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE) + 1)); \
> + PTYPE prod2 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 2), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE) + 2)); \
> + PTYPE prod3 = OP((E1TYPE)EXTRACT(rs1, i * (SCALE) + 3), \
> + (E2TYPE)EXTRACT(rs2, i * (SCALE) + 3)); \
> + rd = INSERT(rd, (OTYPE)(d + prod0 + prod1 + prod2 + prod3), i); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_WIDEN_BINOP(NAME, ETYPE, WTYPE, OTYPE, ELEMS, IBITS, \
> + OBITS, IMASK, OP) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK)); \
> + ETYPE e2 = (ETYPE)((rs2 >> (i * (IBITS))) & (IMASK)); \
> + WTYPE res = OP((WTYPE)0, (WTYPE)e1, (WTYPE)e2); \
> + rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_WIDEN_BINOP_ACC(NAME, ETYPE, WTYPE, OTYPE, ELEMS, \
> + IBITS, OBITS, IMASK, OMASK, OP) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2, \
> + uint64_t dest) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK)); \
> + ETYPE e2 = (ETYPE)((rs2 >> (i * (IBITS))) & (IMASK)); \
> + WTYPE acc = (WTYPE)((dest >> (i * (OBITS))) & (OMASK)); \
> + WTYPE res = OP(acc, (WTYPE)e1, (WTYPE)e2); \
> + rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_WIDEN_MUL(NAME, E1TYPE, E2TYPE, PTYPE, OTYPE, ELEMS, \
> + EXTRACT, OBITS, OP) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i); \
> + PTYPE prod = OP(e1, e2); \
> + rd |= ((uint64_t)(OTYPE)prod) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_WIDEN_MUL_ACC(NAME, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> + OTYPE, ELEMS, EXTRACT, EXTRACTD, OBITS, \
> + OP) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2, \
> + uint64_t dest) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + E1TYPE e1 = (E1TYPE)EXTRACT(rs1, i); \
> + E2TYPE e2 = (E2TYPE)EXTRACT(rs2, i); \
> + DTYPE d = (DTYPE)EXTRACTD(dest, i); \
> + PTYPE prod = OP(e1, e2); \
> + rd |= ((uint64_t)(OTYPE)(d + prod)) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_WIDEN_QMUL_ACC(NAME, ETYPE, DTYPE, PTYPE, STYPE, \
> + OTYPE, ELEMS, EXTRACT, EXTRACTD, SCALE, \
> + OFFSET, SHIFT, ROUND, OBITS, OP) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2, \
> + uint64_t dest) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)EXTRACT(rs1, i * (SCALE) + (OFFSET)); \
> + ETYPE e2 = (ETYPE)EXTRACT(rs2, i * (SCALE) + (OFFSET)); \
> + DTYPE d = (DTYPE)EXTRACTD(dest, i); \
> + PTYPE prod = OP(e1, e2) + (ROUND); \
> + STYPE scaled = (STYPE)(((__int128_t)prod) >> (SHIFT)); \
> + rd |= ((uint64_t)(OTYPE)(d + scaled)) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_DW_2WAY_MUL(NAME, E1TYPE, E2TYPE, PTYPE, EXTRACT, \
> + OFFSET10, OFFSET11, OFFSET20, OFFSET21, \
> + OP, COMBINE) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2) \
> +{ \
> + E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, OFFSET10); \
> + E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, OFFSET11); \
> + E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, OFFSET20); \
> + E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, OFFSET21); \
> + PTYPE prod0 = OP(s1_0, s2_0); \
> + PTYPE prod1 = OP(s1_1, s2_1); \
> + \
> + return (uint64_t)COMBINE(0, prod0, prod1); \
> +}
> +
> +#define GEN_PSIMD_DW_2WAY_MUL_ACC(NAME, E1TYPE, E2TYPE, DTYPE, PTYPE, \
> + EXTRACT, OFFSET10, OFFSET11, OFFSET20, \
> + OFFSET21, OP, COMBINE) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2, \
> + uint64_t dest) \
> +{ \
> + E1TYPE s1_0 = (E1TYPE)EXTRACT(rs1, OFFSET10); \
> + E1TYPE s1_1 = (E1TYPE)EXTRACT(rs1, OFFSET11); \
> + E2TYPE s2_0 = (E2TYPE)EXTRACT(rs2, OFFSET20); \
> + E2TYPE s2_1 = (E2TYPE)EXTRACT(rs2, OFFSET21); \
> + DTYPE d = (DTYPE)dest; \
> + PTYPE prod0 = OP(s1_0, s2_0); \
> + PTYPE prod1 = OP(s1_1, s2_1); \
> + \
> + return (uint64_t)COMBINE(d, prod0, prod1); \
> +}
> +
> +#define GEN_PSIMD_WIDEN_SHIFT(NAME, ETYPE, WTYPE, OTYPE, ELEMS, IBITS, \
> + OBITS, IMASK, SHMASK) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2) \
> +{ \
> + uint64_t rd = 0; \
> + uint8_t shamt = rs2 & (SHMASK); \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((rs1 >> (i * (IBITS))) & (IMASK)); \
> + WTYPE res = (WTYPE)e1 << shamt; \
> + rd |= ((uint64_t)(OTYPE)res) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_DW_ZIP(NAME, EXTRACT, ELEMS, STRIDE, BITS) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1, uint32_t rs2) \
> +{ \
> + uint64_t rd = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + uint64_t e1 = (uint64_t)EXTRACT(rs1, i) << ((STRIDE) * i); \
> + uint64_t e2 = (uint64_t)EXTRACT(rs2, i) \
> + << ((STRIDE) * i + (BITS)); \
> + rd |= e2 | e1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_DW_REDSUM(NAME, SUMTYPE, INITTYPE, ETYPE, EXTRACT, \
> + ELEMS) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint32_t rs1_lo, \
> + uint32_t rs1_hi, uint32_t rs2) \
> +{ \
> + SUMTYPE sum = (INITTYPE)rs2; \
> + uint64_t s1 = ((uint64_t)rs1_hi << 32) | rs1_lo; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + sum += (ETYPE)EXTRACT(s1, i); \
> + } \
> + return (uint32_t)sum; \
> +}
> +
> +#define GEN_PSIMD_NARROW_SRL(NAME, ETYPE, OTYPE, ELEMS, IBITS, OBITS, \
> + IMASK, SHMASK) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint32_t rd = 0; \
> + uint8_t shift = shamt & (SHMASK); \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
> + OTYPE result = (OTYPE)(e1 >> shift); \
> + rd |= ((uint32_t)result) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_NARROW_SRA_PACK(NAME, ETYPE, STYPE, OTYPE, ELEMS, \
> + IBITS, OBITS, IMASK, SHMASK) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint32_t rd = 0; \
> + uint8_t shift = shamt & (SHMASK); \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
> + STYPE shx = (STYPE)e1 >> shift; \
> + OTYPE result = (OTYPE)shx; \
> + rd |= ((uint32_t)result) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_NARROW_RNDSRA_PACK(NAME, ETYPE, STYPE, OTYPE, ELEMS, \
> + IBITS, OBITS, IMASK, SHMASK, RMASK) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint32_t rd = 0; \
> + uint8_t shift = shamt & (SHMASK); \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
> + STYPE e1_s = (STYPE)e1; \
> + uint64_t shx = (((uint64_t)e1_s << 1) >> shift) & (RMASK); \
> + OTYPE result = (OTYPE)((shx + 1) >> 1); \
> + rd |= ((uint32_t)result) << (i * (OBITS)); \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_NCLIP_SIGNED_PACK(NAME, ETYPE, STYPE, CTYPE, OTYPE, \
> + ELEMS, IBITS, OBITS, IMASK, SHMASK, \
> + MIN, MAX, MIN_RES, MAX_RES) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint32_t rd = 0; \
> + uint8_t shift = shamt & (SHMASK); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
> + CTYPE shx = (CTYPE)((STYPE)e1 >> shift); \
> + OTYPE result; \
> + \
> + if (shx < (MIN)) { \
> + sat = 1; \
> + result = (MIN_RES); \
> + } else if (shx > (MAX)) { \
> + sat = 1; \
> + result = (MAX_RES); \
> + } else { \
> + result = (OTYPE)shx; \
> + } \
> + rd |= ((uint32_t)result) << (i * (OBITS)); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_NCLIPR_SIGNED_PACK(NAME, ETYPE, STYPE, CTYPE, OTYPE, \
> + ELEMS, IBITS, OBITS, IMASK, SHMASK, \
> + RMASK, MIN, MAX, MIN_RES, MAX_RES) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint32_t rd = 0; \
> + uint8_t shift = shamt & (SHMASK); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
> + STYPE e1_s = (STYPE)e1; \
> + uint64_t shx = (((uint64_t)e1_s << 1) >> shift) & (RMASK); \
> + CTYPE round_shx = (CTYPE)((shx + 1) >> 1); \
> + OTYPE result; \
> + \
> + if (round_shx < (MIN)) { \
> + sat = 1; \
> + result = (MIN_RES); \
> + } else if (round_shx > (MAX)) { \
> + sat = 1; \
> + result = (MAX_RES); \
> + } else { \
> + result = (OTYPE)round_shx; \
> + } \
> + rd |= ((uint32_t)result) << (i * (OBITS)); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_NCLIP_UNSIGNED_PACK(NAME, ETYPE, WTYPE, OTYPE, ELEMS, \
> + IBITS, OBITS, IMASK, SHMASK, MAX) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint32_t rd = 0; \
> + uint8_t shift = shamt & (SHMASK); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
> + WTYPE shx = (WTYPE)e1 >> shift; \
> + OTYPE result; \
> + \
> + if (shx > (MAX)) { \
> + sat = 1; \
> + result = (OTYPE)(MAX); \
> + } else { \
> + result = (OTYPE)shx; \
> + } \
> + rd |= ((uint32_t)result) << (i * (OBITS)); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_NCLIPR_UNSIGNED_PACK(NAME, ETYPE, WTYPE, OTYPE, ELEMS, \
> + IBITS, OBITS, IMASK, SHMASK, MAX) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint32_t rd = 0; \
> + uint8_t shift = shamt & (SHMASK); \
> + int sat = 0; \
> + \
> + for (int i = 0; i < (ELEMS); i++) { \
> + ETYPE e1 = (ETYPE)((s1 >> (i * (IBITS))) & (IMASK)); \
> + WTYPE shx = ((WTYPE)e1 << 1) >> shift; \
> + WTYPE round_shx = (shx + 1) >> 1; \
> + OTYPE result; \
> + \
> + if (round_shx > (MAX)) { \
> + sat = 1; \
> + result = (OTYPE)(MAX); \
> + } else { \
> + result = (OTYPE)round_shx; \
> + } \
> + rd |= ((uint32_t)result) << (i * (OBITS)); \
> + } \
> + \
> + if (sat) { \
> + env->vxsat = 1; \
> + } \
> + return rd; \
> +}
> +
> +#define GEN_PSIMD_NARROW_SRA(NAME) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + __int128_t s1_s128 = (__int128_t)((int64_t)s1); \
> + __int128_t s1_s96 = (s1_s128 << 32) >> 32; \
> + \
> + return (uint32_t)(s1_s96 >> (shamt & 0x3F)) & 0xFFFFFFFF; \
> +}
> +
> +#define GEN_PSIMD_NARROW_RNDSRA(NAME) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + __int128_t s1_s128 = (__int128_t)((int64_t)s1); \
> + __int128_t s1_s96 = (s1_s128 << 32) >> 32; \
> + __uint128_t shx_97bit = ((__uint128_t)s1_s96 << 1); \
> + uint64_t shx = (uint64_t)(shx_97bit >> (shamt & 0x3F)) & 0x1FFFFFFFF; \
> + \
> + return (uint32_t)((shx + 1) >> 1); \
> +}
> +
> +#define GEN_PSIMD_NARROW_ALIAS(NAME, TARGET) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + return HELPER(TARGET)(env, s1, shamt); \
> +}
> +
> +typedef struct {
> + __uint128_t low;
> + uint8_t high;
> +} PsImdUint129;
> +
> +static inline PsImdUint129 psimd_uint129_lshift1(__int128_t val)
> +{
> + PsImdUint129 result;
> + __uint128_t uval = (__uint128_t)val;
> +
> + result.low = uval << 1;
> + result.high = (uval >> 127) & 0x1;
> + return result;
> +}
> +
> +static inline PsImdUint129 psimd_uint129_rshift(PsImdUint129 val,
> + uint32_t shamt)
> +{
> + PsImdUint129 result;
> +
> + if (shamt == 0) {
> + return val;
> + } else if (shamt >= 129) {
> + result.low = 0;
> + result.high = 0;
> + } else if (shamt == 128) {
> + result.low = val.high;
> + result.high = 0;
> + } else {
> + result.low = (val.low >> shamt) |
> + ((__uint128_t)val.high << (128 - shamt));
> + result.high = val.high >> shamt;
> + }
> + return result;
> +}
> +
> +#define GEN_PSIMD_NCLIP(NAME) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + __int128_t s1_s128 = (__int128_t)((int64_t)s1); \
> + int64_t shx = (int64_t)(s1_s128 >> (shamt & 0x3F)); \
> + \
> + if (shx < -2147483648LL) { \
> + env->vxsat = 1; \
> + return 0x80000000U; \
> + } else if (shx > 2147483647LL) { \
> + env->vxsat = 1; \
> + return 0x7FFFFFFFU; \
> + } else { \
> + return (uint32_t)(shx & 0xFFFFFFFF); \
> + } \
> +}
> +
> +#define GEN_PSIMD_NCLIPR(NAME) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + __int128_t s1_s128 = (__int128_t)((int64_t)s1); \
> + PsImdUint129 shx_129bit = psimd_uint129_lshift1(s1_s128); \
> + PsImdUint129 shx = psimd_uint129_rshift(shx_129bit, shamt & 0x3F); \
> + int64_t round_shx = (int64_t)((shx.low + 1) >> 1); \
> + \
> + if (round_shx < -2147483648LL) { \
> + env->vxsat = 1; \
> + return 0x80000000U; \
> + } else if (round_shx > 2147483647LL) { \
> + env->vxsat = 1; \
> + return 0x7FFFFFFFU; \
> + } else { \
> + return (uint32_t)round_shx; \
> + } \
> +}
> +
> +#define GEN_PSIMD_NCLIPU(NAME) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + uint64_t shx = s1 >> (shamt & 0x3F); \
> + \
> + if (shx > 4294967295ULL) { \
> + env->vxsat = 1; \
> + return 0xFFFFFFFFU; \
> + } else { \
> + return (uint32_t)(shx & 0xFFFFFFFF); \
> + } \
> +}
> +
> +#define GEN_PSIMD_NCLIPRU(NAME) \
> +uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
> +{ \
> + __uint128_t shx_65bit = (__uint128_t)s1 << 1; \
> + __uint128_t shx = shx_65bit >> (shamt & 0x3F); \
> + uint64_t round_shx = (shx + 1) >> 1; \
> + \
> + if (round_shx > 4294967295ULL) { \
> + env->vxsat = 1; \
> + return 0xFFFFFFFFU; \
> + } else { \
> + return (uint32_t)(round_shx & 0xFFFFFFFF); \
> + } \
> +}
> +
> +/* Basic addition operations (non-saturating) */
> +
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework
2026-07-17 10:06 ` [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework Molly Chen
2026-07-26 19:53 ` Daniel Henrique Barboza
2026-07-27 6:16 ` Nutty.Liu
@ 2026-07-29 9:01 ` Chao Liu
2 siblings, 0 replies; 31+ messages in thread
From: Chao Liu @ 2026-07-29 9:01 UTC (permalink / raw)
To: Molly Chen
Cc: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
Chao Liu, qemu-riscv, qemu-devel
On Fri, Jul 17, 2026 at 10:06:55AM +0800, Molly Chen wrote:
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
> ---
> target/riscv/tcg/meson.build | 3 +-
> target/riscv/tcg/psimd_helper.c | 1656 +++++++++++++++++++++++++++++++
> 2 files changed, 1658 insertions(+), 1 deletion(-)
> create mode 100644 target/riscv/tcg/psimd_helper.c
>
> diff --git a/target/riscv/tcg/meson.build b/target/riscv/tcg/meson.build
> index a05ab642f41..cc438d7c0d2 100644
> --- a/target/riscv/tcg/meson.build
> +++ b/target/riscv/tcg/meson.build
> @@ -15,7 +15,8 @@ riscv_ss.add(files(
> 'vcrypto_helper.c',
> 'vector_helper.c',
> 'vector_internals.c',
> - 'zce_helper.c'))
> + 'zce_helper.c',
> + 'psimd_helper.c'))
>
>
> riscv_system_ss.add(files(
> diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
> new file mode 100644
> index 00000000000..2948bbb2a86
> --- /dev/null
> +++ b/target/riscv/tcg/psimd_helper.c
> @@ -0,0 +1,1656 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/* RISC-V Packed SIMD Extension Helpers for QEMU. */
> +/* Copyright (C) 2026 ISRC ISCAS. */
> +
> +#include "qemu/osdep.h"
> +#include "cpu.h"
> +#include "qemu/host-utils.h"
> +#include "exec/helper-proto.h"
> +#include "fpu/softfloat.h"
> +#include "internals.h"
> +
> +
> +/* Helper macros */
> +
> +/* Element count calculations */
> +#define ELEMS_B(target) (sizeof(target) * 8 / 8) /* byte elements count */
> +#define ELEMS_H(target) (sizeof(target) * 8 / 16)
> +#define ELEMS_W(target) (sizeof(target) * 8 / 32) /* word elements count */
> +#define ELEMS_D(target) (sizeof(target) * 8 / 64)
> +
> +/* Element extraction macros - unsigned to avoid sign extension */
> +#define EXTRACT8(val, idx) (((val) >> ((idx) * 8)) & 0xFF)
> +#define EXTRACT16(val, idx) (((val) >> ((idx) * 16)) & 0xFFFF)
> +#define EXTRACT32(val, idx) (((val) >> ((idx) * 32)) & 0xFFFFFFFF)
> +#define EXTRACT64(val, idx) (((val) >> ((idx) * 64)) & 0xFFFFFFFFFFFFFFFFULL)
> +
QEMU has the generator bit-operation helper macros. I believe you don't need to
define them again, so you can just follow this header file path.
path: include/qemu/bitops.h
```
extract8(value, start, length)
extract16(value, start, length)
extract32(value, start, length)
extract64(value, start, length)
sextract32(value, start, length)
sextract64(value, start, length)
```
So we can redefine these helper macros like this:
```
#define EXTRACT_B(val, idx) extract64((val), (idx) * 8, 8)
#define EXTRACT_H(val, idx) extract64((val), (idx) * 16, 16)
#define EXTRACT_W(val, idx) extract64((val), (idx) * 32, 32)
#define EXTRACT_D(val, idx) extract64((val), (idx) * 64, 64)
```
> +/* Element insertion macros */
> +#define INSERT8(val, res, idx) \
> + ((val) | ((target_ulong)(uint8_t)(res) << ((idx) * 8)))
> +#define INSERT16(val, res, idx) \
> + ((val) | ((target_ulong)(uint16_t)(res) << ((idx) * 16)))
> +#define INSERT32(val, res, idx) \
> + ((val) | ((target_ulong)(uint32_t)(res) << ((idx) * 32)))
> +#define INSERT32_64(val, res, idx) \
> + ((val) | ((uint64_t)(uint32_t)(res) << ((idx) * 32)))
> +#define INSERT64(val, res, idx) \
> + ((val) | ((uint64_t)(res) << ((idx) * 64)))
> +
> +/* Saturation constants */
> +static const int8_t SAT_MAX_B = 127;
> +static const int8_t SAT_MIN_B = -128;
> +static const int16_t SAT_MAX_H = 32767;
> +static const int16_t SAT_MIN_H = -32768;
> +static const int32_t SAT_MAX_W = 2147483647;
> +static const int32_t SAT_MIN_W = -2147483648LL;
> +static const uint8_t USAT_MAX_B = 255;
> +static const uint16_t USAT_MAX_H = 65535;
> +static const uint32_t USAT_MAX_W = 4294967295U;
> +
> +
> +/* Saturation helper functions */
> +
> +/**
> + * Signed saturation for 8-bit elements
> + * Returns saturated value and sets *sat if saturation occurred
> + */
This helper function has some comments that explain what it does.
I believe we don't need these explanations if the function name is
already clear.
The other helper functions below are similar. I think we only need
to add comments when it's necessary to explain the reasoning behind
why we're doing something.
d> +static inline int8_t signed_saturate_b(int32_t val, int *sat)
> +{
> + if (val > SAT_MAX_B) {
> + *sat = 1;
> + return SAT_MAX_B;
> + }
> + if (val < SAT_MIN_B) {
> + *sat = 1;
> + return SAT_MIN_B;
> + }
> + return (int8_t)val;
> +}
> +
> +/**
> + * Signed saturation for 16-bit elements
> + */
> +static inline int16_t signed_saturate_h(int32_t val, int *sat)
> +{
> + if (val > SAT_MAX_H) {
> + *sat = 1;
> + return SAT_MAX_H;
> + }
> + if (val < SAT_MIN_H) {
> + *sat = 1;
> + return SAT_MIN_H;
> + }
> + return (int16_t)val;
> +}
> +
> +/**
> + * Signed saturation for 32-bit elements
> + */
> +static inline int32_t signed_saturate_w(int64_t val, int *sat)
> +{
> + if (val > SAT_MAX_W) {
> + *sat = 1;
> + return SAT_MAX_W;
> + }
> + if (val < SAT_MIN_W) {
> + *sat = 1;
> + return SAT_MIN_W;
> + }
> + return (int32_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 8-bit elements
> + */
> +static inline uint8_t unsigned_saturate_b(uint32_t val, int *sat)
> +{
> + if (val > USAT_MAX_B) {
> + *sat = 1;
> + return USAT_MAX_B;
> + }
> + return (uint8_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 16-bit elements
> + */
> +static inline uint16_t unsigned_saturate_h(uint32_t val, int *sat)
> +{
> + if (val > USAT_MAX_H) {
> + *sat = 1;
> + return USAT_MAX_H;
> + }
> + return (uint16_t)val;
> +}
> +
> +/**
> + * Unsigned saturation for 32-bit elements
> + */
> +static inline uint32_t unsigned_saturate_w(uint64_t val, int *sat)
> +{
> + if (val > USAT_MAX_W) {
> + *sat = 1;
> + return USAT_MAX_W;
> + }
> + return (uint32_t)val;
> +}
> +
> +static inline target_ulong psimd_abdsumu_b(target_ulong rs1,
> + target_ulong rs2,
> + target_ulong sum)
> +{
> + int elems = ELEMS_B(rs1);
> +
> + for (int i = 0; i < elems; i++) {
> + uint8_t e1 = EXTRACT8(rs1, i);
> + uint8_t e2 = EXTRACT8(rs2, i);
> + uint8_t diff = (e1 > e2) ? (e1 - e2) : (e2 - e1);
> + sum += diff;
> + }
> +
> + return sum;
> +}
> +
> +#define PSIMD_DO_ADD(N, M) ((N) + (M))
> +#define PSIMD_DO_SUB(N, M) ((N) - (M))
> +#define PSIMD_DO_ABD(N, M) ((N) >= (M) ? (N) - (M) : (M) - (N))
> +#define PSIMD_DO_EQ_MASK(N, M) ((N) == (M) ? -1 : 0)
> +#define PSIMD_DO_LT_MASK(N, M) ((N) < (M) ? -1 : 0)
> +#define PSIMD_DO_MIN(N, M) ((N) < (M) ? (N) : (M))
> +#define PSIMD_DO_MAX(N, M) ((N) > (M) ? (N) : (M))
> +#define PSIMD_DO_SLL(N, M) ((N) << (M))
> +#define PSIMD_DO_SRL(N, M) ((N) >> (M))
> +#define PSIMD_DO_SRA(N, M) ((N) >> (M))
> +
[...]
> +
> +#define GEN_PSIMD_SCALAR_ABS(NAME, RTYPE, STYPE, UTYPE) \
> +RTYPE HELPER(NAME)(CPURISCVState *env, RTYPE rs1) \
> +{ \
> + STYPE value = (STYPE)rs1; \
> + UTYPE result = (UTYPE)value; \
> + \
> + if (value < 0) { \
> + result = (UTYPE)0 - result; \
> + } \
> + return (RTYPE)(STYPE)result; \
> +}
The '\' for the column widths aren't aligned here. It would
look much better if we could align them consistently throughout.
[...]
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
> +{ \
> + int64_t a = (int64_t)rs1; \
> + int8_t shamt = (int8_t)(rs2 & 0xff); \
> + \
> + if (shamt >= 0) { \
> + return (uint64_t)(a << shamt); \
> + } \
> + \
> + int right = -shamt; \
> + if (right >= 64) { \
> + return (a < 0) ? (uint64_t)-1 : 0; \
> + } \
> + return (uint64_t)RIGHT_OP(a, right); \
> +}
There are similar alignment issues here.
> +
> +#define PSIMD_DO_SRL64(A, B) (((B) >= 64) ? 0 : ((A) >> (B)))
> +#define PSIMD_DO_RNDSRL64(A, B) \
> + (((B) > 64) ? 0 : ((((A) >> ((B) - 1)) + 1) >> 1))
> +
> +#define GEN_PSIMD_VAR_SRL64(NAME, RIGHT_OP) \
> +uint64_t HELPER(NAME)(CPURISCVState *env, uint64_t rs1, uint64_t rs2) \
> +{ \
> + int8_t shamt = (int8_t)(rs2 & 0xff); \
> + \
> + if (shamt < 0) { \
> + return RIGHT_OP(rs1, -shamt); \
> + } \
> + return (shamt >= 64) ? 0 : (rs1 << shamt); \
> +}
> +
Same here.You can check again for the patches.
Thanks,
Chao
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
2026-07-17 10:06 ` [PATCH v2 01/18] target/riscv: Add packed SIMD extension state Molly Chen
2026-07-17 10:06 ` [PATCH v2 02/18] target/riscv: Add packed SIMD helper framework Molly Chen
@ 2026-07-17 10:06 ` Molly Chen
2026-07-26 22:05 ` Daniel Henrique Barboza
` (2 more replies)
2026-07-17 10:06 ` [PATCH v2 04/18] target/riscv: Add packed SIMD averaging and rounding instructions Molly Chen
` (16 subsequent siblings)
19 siblings, 3 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:06 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/helper.h | 41 ++
target/riscv/insn32.decode | 63 +++
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 547 ++++++++++++++++++++
target/riscv/tcg/psimd_helper.c | 114 ++++
target/riscv/tcg/translate.c | 4 +
5 files changed, 769 insertions(+)
create mode 100644 target/riscv/tcg/insn_trans/trans_rvp.c.inc
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 542b7c264fc..eebb2febd95 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1358,3 +1358,44 @@ DEF_HELPER_1(ssamoswap_disabled, void, env)
/* Zalrsc SC write probe */
DEF_HELPER_FLAGS_3(sc_probe_write, TCG_CALL_NO_WG, void, env, tl, tl)
+
+/* Packed SIMD */
+/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
+DEF_HELPER_3(padd_b, tl, env, tl, tl)
+DEF_HELPER_3(padd_h, tl, env, tl, tl)
+DEF_HELPER_3(padd_w, i64, env, i64, i64)
+DEF_HELPER_3(padd_bs, tl, env, tl, tl)
+DEF_HELPER_3(padd_hs, tl, env, tl, tl)
+DEF_HELPER_3(padd_ws, i64, env, i64, i64)
+DEF_HELPER_3(psub_b, tl, env, tl, tl)
+DEF_HELPER_3(psub_h, tl, env, tl, tl)
+DEF_HELPER_3(psub_w, i64, env, i64, i64)
+DEF_HELPER_3(psh1add_h, tl, env, tl, tl)
+DEF_HELPER_3(psh1add_w, i64, env, i64, i64)
+DEF_HELPER_3(pssh1sadd_h, tl, env, tl, tl)
+DEF_HELPER_3(pssh1sadd_w, i64, env, i64, i64)
+DEF_HELPER_3(ssh1sadd, i32, env, i32, i32)
+DEF_HELPER_3(psadd_b, tl, env, tl, tl)
+DEF_HELPER_3(psadd_h, tl, env, tl, tl)
+DEF_HELPER_3(psadd_w, i64, env, i64, i64)
+DEF_HELPER_3(psaddu_b, tl, env, tl, tl)
+DEF_HELPER_3(psaddu_h, tl, env, tl, tl)
+DEF_HELPER_3(psaddu_w, i64, env, i64, i64)
+DEF_HELPER_3(sadd, i32, env, i32, i32)
+DEF_HELPER_3(saddu, i32, env, i32, i32)
+DEF_HELPER_3(pssub_b, tl, env, tl, tl)
+DEF_HELPER_3(pssub_h, tl, env, tl, tl)
+DEF_HELPER_3(pssub_w, i64, env, i64, i64)
+DEF_HELPER_3(pssubu_b, tl, env, tl, tl)
+DEF_HELPER_3(pssubu_h, tl, env, tl, tl)
+DEF_HELPER_3(pssubu_w, i64, env, i64, i64)
+DEF_HELPER_3(ssub, i32, env, i32, i32)
+DEF_HELPER_3(ssubu, i32, env, i32, i32)
+DEF_HELPER_3(psati_h, tl, env, tl, tl)
+DEF_HELPER_3(pusati_h, tl, env, tl, tl)
+DEF_HELPER_3(psati_w, i64, env, i64, i64)
+DEF_HELPER_3(pusati_w, i64, env, i64, i64)
+DEF_HELPER_3(sati_32, i32, env, i32, i32)
+DEF_HELPER_3(usati_32, i32, env, i32, i32)
+DEF_HELPER_3(sati_64, i64, env, i64, i64)
+DEF_HELPER_3(usati_64, i64, env, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 21272fdb504..8da13669d73 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -40,6 +40,9 @@
%imm_z6 26:1 15:5
%imm_mop5 30:1 26:2 20:2
%imm_mop3 30:1 26:2
+%imm_p_ui16 20:4
+%imm_p_ui32 20:5
+%imm_p_ui64 20:6
# Argument sets:
&empty
@@ -60,6 +63,7 @@
&k_aes shamt rs2 rs1 rd
&mop5 imm rd rs1
&mop3 imm rd rs1 rs2
+&p_ui imm rs1 rd
# Formats 32:
@r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd
@@ -105,6 +109,10 @@
@mop5 . . .. .. .... .. ..... ... ..... ....... &mop5 imm=%imm_mop5 %rd %rs1
@mop3 . . .. .. . ..... ..... ... ..... ....... &mop3 imm=%imm_mop3 %rd %rs1 %rs2
+@p_ui16 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui16 %rs1 %rd
+@p_ui32 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui32 %rs1 %rd
+@p_ui64 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui64 %rs1 %rd
+
# Formats 64:
@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd
@@ -1084,3 +1092,58 @@ sb_aqrl 00111 . . ..... ..... 000 ..... 0101111 @atom_st
sh_aqrl 00111 . . ..... ..... 001 ..... 0101111 @atom_st
sw_aqrl 00111 . . ..... ..... 010 ..... 0101111 @atom_st
sd_aqrl 00111 . . ..... ..... 011 ..... 0101111 @atom_st
+
+# *** P Experimental Extension Version v020 ***
+# Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating)
+padd_b 1000010 ..... ..... 000 ..... 0111011 @r
+padd_h 1000000 ..... ..... 000 ..... 0111011 @r
+padd_w 1000001 ..... ..... 000 ..... 0111011 @r
+padd_bs 1001110 ..... ..... 010 ..... 0011011 @r
+padd_hs 1001100 ..... ..... 010 ..... 0011011 @r
+padd_ws 1001101 ..... ..... 010 ..... 0011011 @r
+psub_b 1100010 ..... ..... 000 ..... 0111011 @r
+psub_h 1100000 ..... ..... 000 ..... 0111011 @r
+psub_w 1100001 ..... ..... 000 ..... 0111011 @r
+psh1add_h 1010000 ..... ..... 010 ..... 0111011 @r
+psh1add_w 1010001 ..... ..... 010 ..... 0111011 @r
+pssh1sadd_h 1011000 ..... ..... 010 ..... 0111011 @r
+{
+ ssh1sadd 1011001 ..... ..... 010 ..... 0111011 @r
+ pssh1sadd_w 1011001 ..... ..... 010 ..... 0111011 @r
+}
+psadd_b 1001010 ..... ..... 000 ..... 0111011 @r
+psadd_h 1001000 ..... ..... 000 ..... 0111011 @r
+{
+ sadd 1001001 ..... ..... 000 ..... 0111011 @r
+ psadd_w 1001001 ..... ..... 000 ..... 0111011 @r
+}
+psaddu_b 1011010 ..... ..... 000 ..... 0111011 @r
+psaddu_h 1011000 ..... ..... 000 ..... 0111011 @r
+{
+ saddu 1011001 ..... ..... 000 ..... 0111011 @r
+ psaddu_w 1011001 ..... ..... 000 ..... 0111011 @r
+}
+pssub_b 1101010 ..... ..... 000 ..... 0111011 @r
+pssub_h 1101000 ..... ..... 000 ..... 0111011 @r
+{
+ ssub 1101001 ..... ..... 000 ..... 0111011 @r
+ pssub_w 1101001 ..... ..... 000 ..... 0111011 @r
+}
+pssubu_b 1111010 ..... ..... 000 ..... 0111011 @r
+pssubu_h 1111000 ..... ..... 000 ..... 0111011 @r
+{
+ ssubu 1111001 ..... ..... 000 ..... 0111011 @r
+ pssubu_w 1111001 ..... ..... 000 ..... 0111011 @r
+}
+psati_h 11100 001.... ..... 100 ..... 0011011 @p_ui16
+pusati_h 10100 001.... ..... 100 ..... 0011011 @p_ui16
+{
+ sati_32 11100 01..... ..... 100 ..... 0011011 @p_ui32
+ psati_w 11100 01..... ..... 100 ..... 0011011 @p_ui32
+}
+{
+ usati_32 10100 01..... ..... 100 ..... 0011011 @p_ui32
+ pusati_w 10100 01..... ..... 100 ..... 0011011 @p_ui32
+}
+sati_64 111001 ...... ..... 100 ..... 0011011 @p_ui64
+usati_64 101001 ...... ..... 100 ..... 0011011 @p_ui64
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
new file mode 100644
index 00000000000..056ccfb486e
--- /dev/null
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -0,0 +1,547 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* RISC-V translation routines for the P Standard Extensions. */
+/* Copyright (c) 2026 ISRC ISCAS. */
+
+/* Save a 64 bit data in src to dst and dst + 1 */
+
+static bool require_rvp(DisasContext *ctx)
+{
+ uint32_t opcode = ctx->opcode & 0x7f;
+
+ if (!has_ext(ctx, RVP)) {
+ return false;
+ }
+
+ /*
+ * P_VXSAT_EXCP is encoded in the TB flags only when P is implemented
+ * without Zve*, where stateen0.VXSAT controls the whole OP-32 and
+ * OP-IMM-32 P instruction spaces. When Zve* is present, this field
+ * remains NONE and vxsat access is checked by the VS path instead.
+ */
+ if ((opcode == 0x3b || opcode == 0x1b) &&
+ ctx->p_vxsat_excp != P_VXSAT_EXCP_NONE) {
+ ctx->virt_inst_excp =
+ ctx->p_vxsat_excp == P_VXSAT_EXCP_VIRTUAL;
+ return false;
+ }
+
+ return true;
+}
+
+static bool prepare_rvp_vxsat(DisasContext *ctx)
+{
+ if (!ctx->cfg_ptr->ext_zve32x) {
+ return true;
+ }
+
+ if (ctx->mstatus_vs == EXT_STATUS_DISABLED) {
+ return false;
+ }
+
+ mark_vs_dirty(ctx);
+ return true;
+}
+
+#define REQUIRE_RVP(ctx) do { \
+ if (!require_rvp(ctx)) { \
+ return false; \
+ } \
+} while (0)
+
+#define GEN_SIMD_TRANS_BODY(NAME, VXSAT) \
+do { \
+ REQUIRE_RVP(ctx); \
+ if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
+ return false; \
+ } \
+ TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
+ TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
+ TCGv dest = dest_gpr(ctx, a->rd); \
+ gen_helper_##NAME(dest, tcg_env, src1, src2); \
+ gen_set_gpr(ctx, a->rd, dest); \
+ return true; \
+} while (0)
+
+#define GEN_SIMD_TRANS_UNAVAILABLE_32(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ return true; \
+}
+
+#define GEN_SIMD_TRANS_UNAVAILABLE_64(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_64BIT(ctx); \
+ return true; \
+}
+
+#define GEN_SIMD_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ GEN_SIMD_TRANS_BODY(NAME, false); \
+}
+
+#define GEN_SIMD_TRANS_VXSAT(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ GEN_SIMD_TRANS_BODY(NAME, true); \
+}
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_32(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ GEN_SIMD_TRANS_BODY(NAME, false); \
+}
+#define GEN_SIMD_TRANS_32_VXSAT(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ GEN_SIMD_TRANS_BODY(NAME, true); \
+}
+#else
+#define GEN_SIMD_TRANS_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#define GEN_SIMD_TRANS_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
+#define GEN_SIMD_TRANS_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
+#else
+#define GEN_SIMD_TRANS_64(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_64BIT(ctx); \
+ GEN_SIMD_TRANS_BODY(NAME, false); \
+}
+#define GEN_SIMD_TRANS_64_VXSAT(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_64BIT(ctx); \
+ GEN_SIMD_TRANS_BODY(NAME, true); \
+}
+#endif
+
+#define GEN_SIMD_TRANS_ACC_BODY(NAME, VXSAT) \
+do { \
+ REQUIRE_RVP(ctx); \
+ if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
+ return false; \
+ } \
+ TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
+ TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
+ TCGv dest = dest_gpr(ctx, a->rd); \
+ TCGv t = tcg_temp_new(); \
+ gen_helper_##NAME(t, tcg_env, src1, src2, dest); \
+ gen_set_gpr(ctx, a->rd, t); \
+ return true; \
+} while (0)
+
+#define GEN_SIMD_TRANS_ACC(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ GEN_SIMD_TRANS_ACC_BODY(NAME, false); \
+}
+
+#define GEN_SIMD_TRANS_ACC_VXSAT(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ GEN_SIMD_TRANS_ACC_BODY(NAME, true); \
+}
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_ACC_32(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ GEN_SIMD_TRANS_ACC_BODY(NAME, false); \
+}
+#else
+#define GEN_SIMD_TRANS_ACC_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_ACC_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
+#else
+#define GEN_SIMD_TRANS_ACC_64(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_64BIT(ctx); \
+ GEN_SIMD_TRANS_ACC_BODY(NAME, false); \
+}
+#endif
+
+#define GEN_SIMD_TRANS_R1_BODY(NAME, VXSAT) \
+do { \
+ REQUIRE_RVP(ctx); \
+ if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
+ return false; \
+ } \
+ TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
+ TCGv dest = dest_gpr(ctx, a->rd); \
+ gen_helper_##NAME(dest, tcg_env, src1); \
+ gen_set_gpr(ctx, a->rd, dest); \
+ return true; \
+} while (0)
+
+#define GEN_SIMD_TRANS_R1(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ GEN_SIMD_TRANS_R1_BODY(NAME, false); \
+}
+
+#define GEN_SIMD_TRANS_R1_VXSAT(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ GEN_SIMD_TRANS_R1_BODY(NAME, true); \
+}
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_R1_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
+#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
+#else
+#define GEN_SIMD_TRANS_R1_64(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_64BIT(ctx); \
+ GEN_SIMD_TRANS_R1_BODY(NAME, false); \
+}
+#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_64BIT(ctx); \
+ GEN_SIMD_TRANS_R1_BODY(NAME, true); \
+}
+#endif
+
+#define GEN_SIMD_TRANS_IMM_BODY(NAME, VXSAT) \
+do { \
+ REQUIRE_RVP(ctx); \
+ if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
+ return false; \
+ } \
+ TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
+ TCGv imm = tcg_constant_tl(a->imm); \
+ TCGv dest = dest_gpr(ctx, a->rd); \
+ gen_helper_##NAME(dest, tcg_env, src1, imm); \
+ gen_set_gpr(ctx, a->rd, dest); \
+ return true; \
+} while (0)
+
+#define GEN_SIMD_TRANS_IMM(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ GEN_SIMD_TRANS_IMM_BODY(NAME, false); \
+}
+
+#define GEN_SIMD_TRANS_IMM_VXSAT(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ GEN_SIMD_TRANS_IMM_BODY(NAME, true); \
+}
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_IMM_32(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ GEN_SIMD_TRANS_IMM_BODY(NAME, false); \
+}
+#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ GEN_SIMD_TRANS_IMM_BODY(NAME, true); \
+}
+#else
+#define GEN_SIMD_TRANS_IMM_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_IMM_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
+#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
+#else
+#define GEN_SIMD_TRANS_IMM_64(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_64BIT(ctx); \
+ GEN_SIMD_TRANS_IMM_BODY(NAME, false); \
+}
+#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_64BIT(ctx); \
+ GEN_SIMD_TRANS_IMM_BODY(NAME, true); \
+}
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, SRC2) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ REQUIRE_RVP(ctx); \
+ TCGv_i32 src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
+ TCGv_i32 src2 = SRC2; \
+ TCGv_i64 t = tcg_temp_new_i64(); \
+ gen_helper_##NAME(t, tcg_env, src1, src2); \
+ set_pair_regs(ctx, (a->rd) * 2, t); \
+ return true; \
+}
+
+#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) \
+ GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE))
+
+#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) \
+ GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, tcg_constant_i32(a->imm))
+#else
+#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, SRC2_0, SRC2_1, VXSAT) \
+static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ REQUIRE_RVP(ctx); \
+ if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
+ return false; \
+ } \
+ TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
+ TCGv src2_0 = SRC2_0; \
+ TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2); \
+ TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
+ TCGv src2_1 = SRC2_1; \
+ TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1); \
+ gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2_0); \
+ gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2_1); \
+ gen_set_gpr(ctx, (a->rd) * 2, dest_0); \
+ gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1); \
+ return true; \
+}
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER) \
+ GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
+ get_gpr(ctx, (a->rs2) * 2, EXT_NONE), \
+ get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), false)
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER) \
+ GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
+ get_gpr(ctx, (a->rs2) * 2, EXT_NONE), \
+ get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), true)
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER) \
+ GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
+ tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), false)
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER) \
+ GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
+ tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), true)
+#else
+#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER) \
+ GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER) \
+ GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER) \
+ GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER) \
+ GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, VXSAT) \
+static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ REQUIRE_RVP(ctx); \
+ if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
+ return false; \
+ } \
+ TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
+ TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2); \
+ TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
+ TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1); \
+ TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
+ gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2); \
+ gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2); \
+ gen_set_gpr(ctx, (a->rd) * 2, dest_0); \
+ gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1); \
+ return true; \
+}
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER) \
+ GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, false)
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER) \
+ GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, true)
+#else
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER) \
+ GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER) \
+ GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, VXSAT) \
+static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a) \
+{ \
+ REQUIRE_RVP(ctx); \
+ if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
+ return false; \
+ } \
+ TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
+ TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2); \
+ TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
+ TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1); \
+ gen_helper_##HELPER(dest_0, tcg_env, src1_0); \
+ gen_helper_##HELPER(dest_1, tcg_env, src1_1); \
+ gen_set_gpr(ctx, (a->rd) * 2, dest_0); \
+ gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1); \
+ return true; \
+}
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER) \
+ GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, false)
+
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER) \
+ GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, true)
+#else
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER) \
+ GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER) \
+ GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ REQUIRE_RVP(ctx); \
+ TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
+ TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
+ TCGv_i64 t = tcg_temp_new_i64(); \
+ if (a->rd == 0) { \
+ tcg_gen_movi_i64(t, 0); \
+ } else { \
+ get_pair_regs(ctx, t, (a->rd) * 2); \
+ } \
+ gen_helper_##NAME(t, tcg_env, src1, src2, t); \
+ set_pair_regs(ctx, (a->rd) * 2, t); \
+ return true; \
+}
+#else
+#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ REQUIRE_RVP(ctx); \
+ TCGv_i32 src1_l; \
+ TCGv_i32 src1_h; \
+ TCGv_i32 src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
+ TCGv_i32 dest = dest_gpr(ctx, a->rd); \
+ if (a->rs1 == 0) { \
+ src1_l = tcg_temp_new_i32(); \
+ src1_h = tcg_temp_new_i32(); \
+ tcg_gen_movi_i32(src1_l, 0); \
+ tcg_gen_movi_i32(src1_h, 0); \
+ } else { \
+ src1_l = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
+ src1_h = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
+ } \
+ gen_helper_##NAME(dest, tcg_env, src1_l, src1_h, src2); \
+ gen_set_gpr(ctx, a->rd, dest); \
+ return true; \
+}
+#else
+#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#endif
+
+#if defined(TARGET_RISCV32)
+#define GEN_SIMD_TRANS_PN_OP(NAME, SRC2, VXSAT) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ REQUIRE_RVP(ctx); \
+ if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
+ return false; \
+ } \
+ TCGv_i64 s1 = tcg_temp_new_i64(); \
+ if (a->rs1 == 0) { \
+ tcg_gen_mov_i64(s1, 0); \
+ } else { \
+ get_pair_regs(ctx, s1, a->rs1 * 2); \
+ } \
+ TCGv src2 = SRC2; \
+ TCGv dest = dest_gpr(ctx, a->rd); \
+ gen_helper_##NAME(dest, tcg_env, s1, src2); \
+ gen_set_gpr(ctx, a->rd, dest); \
+ return true; \
+}
+
+#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) \
+ GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), false)
+
+#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) \
+ GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), true)
+
+#define GEN_SIMD_TRANS_PN_OP_REG(NAME) \
+ GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), false)
+
+#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) \
+ GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), true)
+#else
+#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#define GEN_SIMD_TRANS_PN_OP_REG(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
+#endif
+
+/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
+GEN_SIMD_TRANS(padd_b)
+GEN_SIMD_TRANS(padd_h)
+GEN_SIMD_TRANS_64(padd_w)
+GEN_SIMD_TRANS(padd_bs)
+GEN_SIMD_TRANS(padd_hs)
+GEN_SIMD_TRANS_64(padd_ws)
+GEN_SIMD_TRANS(psub_b)
+GEN_SIMD_TRANS(psub_h)
+GEN_SIMD_TRANS_64(psub_w)
+GEN_SIMD_TRANS(psh1add_h)
+GEN_SIMD_TRANS_64(psh1add_w)
+GEN_SIMD_TRANS_VXSAT(pssh1sadd_h)
+GEN_SIMD_TRANS_64_VXSAT(pssh1sadd_w)
+GEN_SIMD_TRANS_32_VXSAT(ssh1sadd)
+GEN_SIMD_TRANS_VXSAT(psadd_b)
+GEN_SIMD_TRANS_VXSAT(psadd_h)
+GEN_SIMD_TRANS_64_VXSAT(psadd_w)
+GEN_SIMD_TRANS_VXSAT(psaddu_b)
+GEN_SIMD_TRANS_VXSAT(psaddu_h)
+GEN_SIMD_TRANS_64_VXSAT(psaddu_w)
+GEN_SIMD_TRANS_32_VXSAT(sadd)
+GEN_SIMD_TRANS_32_VXSAT(saddu)
+GEN_SIMD_TRANS_VXSAT(pssub_b)
+GEN_SIMD_TRANS_VXSAT(pssub_h)
+GEN_SIMD_TRANS_64_VXSAT(pssub_w)
+GEN_SIMD_TRANS_VXSAT(pssubu_b)
+GEN_SIMD_TRANS_VXSAT(pssubu_h)
+GEN_SIMD_TRANS_64_VXSAT(pssubu_w)
+GEN_SIMD_TRANS_32_VXSAT(ssub)
+GEN_SIMD_TRANS_32_VXSAT(ssubu)
+GEN_SIMD_TRANS_IMM_VXSAT(psati_h)
+GEN_SIMD_TRANS_IMM_VXSAT(pusati_h)
+GEN_SIMD_TRANS_IMM_64_VXSAT(psati_w)
+GEN_SIMD_TRANS_IMM_64_VXSAT(pusati_w)
+GEN_SIMD_TRANS_IMM_32_VXSAT(sati_32)
+GEN_SIMD_TRANS_IMM_32_VXSAT(usati_32)
+GEN_SIMD_TRANS_IMM_64_VXSAT(sati_64)
+GEN_SIMD_TRANS_IMM_64_VXSAT(usati_64)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 2948bbb2a86..52c58e0287e 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -1654,3 +1654,117 @@ uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
/* Basic addition operations (non-saturating) */
+GEN_PSIMD_BINOP(padd_b, target_ulong, uint8_t, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
+GEN_PSIMD_BINOP(padd_h, target_ulong, uint16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
+GEN_PSIMD_BINOP(padd_w, uint64_t, uint32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
+
+GEN_PSIMD_BINOP_SCALAR(padd_bs, target_ulong, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
+GEN_PSIMD_BINOP_SCALAR(padd_hs, target_ulong, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
+GEN_PSIMD_BINOP_SCALAR(padd_ws, uint64_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
+
+/* Basic subtraction operations (non-saturating) */
+
+GEN_PSIMD_BINOP(psub_b, target_ulong, uint8_t, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
+GEN_PSIMD_BINOP(psub_h, target_ulong, uint16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
+GEN_PSIMD_BINOP(psub_w, uint64_t, uint32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
+
+/* Shift-left-by-one and add operations */
+
+GEN_PSIMD_SHADD(psh1add_h, target_ulong, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, 1)
+GEN_PSIMD_SHADD(psh1add_w, uint64_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 1)
+
+GEN_PSIMD_SAT_SHADD(pssh1sadd_h, target_ulong, int16_t, int32_t,
+ EXTRACT16, INSERT16, ELEMS_H, 1, -0x4000, 0x3fff,
+ SAT_MIN_H, SAT_MAX_H, signed_saturate_h)
+GEN_PSIMD_SAT_SHADD(pssh1sadd_w, uint64_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
+ 0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
+
+GEN_PSIMD_SAT_SHADD(ssh1sadd, uint32_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
+ 0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
+
+/* Saturating addition operations */
+
+GEN_PSIMD_SAT_BINOP(psadd_b, target_ulong, int8_t, int32_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
+ signed_saturate_b)
+GEN_PSIMD_SAT_BINOP(psadd_h, target_ulong, int16_t, int32_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
+ signed_saturate_h)
+GEN_PSIMD_SAT_BINOP(psadd_w, uint64_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
+ signed_saturate_w)
+
+GEN_PSIMD_SAT_BINOP(psaddu_b, target_ulong, uint8_t, uint32_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
+ unsigned_saturate_b)
+GEN_PSIMD_SAT_BINOP(psaddu_h, target_ulong, uint16_t, uint32_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
+ unsigned_saturate_h)
+GEN_PSIMD_SAT_BINOP(psaddu_w, uint64_t, uint32_t, uint64_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
+ unsigned_saturate_w)
+
+GEN_PSIMD_SAT_BINOP(sadd, uint32_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
+ signed_saturate_w)
+GEN_PSIMD_SAT_BINOP(saddu, uint32_t, uint32_t, uint64_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
+ unsigned_saturate_w)
+
+/* Saturating subtraction operations */
+
+GEN_PSIMD_SAT_BINOP(pssub_b, target_ulong, int8_t, int32_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB,
+ signed_saturate_b)
+GEN_PSIMD_SAT_BINOP(pssub_h, target_ulong, int16_t, int32_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB,
+ signed_saturate_h)
+GEN_PSIMD_SAT_BINOP(pssub_w, uint64_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
+ signed_saturate_w)
+
+GEN_PSIMD_USUB_SAT(pssubu_b, target_ulong, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B)
+GEN_PSIMD_USUB_SAT(pssubu_h, target_ulong, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H)
+GEN_PSIMD_USUB_SAT(pssubu_w, uint64_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W)
+
+GEN_PSIMD_SAT_BINOP(ssub, uint32_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
+ signed_saturate_w)
+GEN_PSIMD_USUB_SAT(ssubu, uint32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W)
+
+/* Saturation instructions (SAT, USAT) */
+
+GEN_PSIMD_SATI(psati_h, target_ulong, int16_t, int64_t,
+ EXTRACT16, INSERT16, ELEMS_H, 0x0f)
+GEN_PSIMD_USATI(pusati_h, target_ulong, int16_t, uint16_t, uint32_t,
+ EXTRACT16, INSERT16, ELEMS_H, 1U)
+GEN_PSIMD_SATI(psati_w, uint64_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x1f)
+GEN_PSIMD_USATI(pusati_w, uint64_t, int32_t, uint32_t, uint64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 1ULL)
+GEN_PSIMD_SATI(sati_32, uint32_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x1f)
+GEN_PSIMD_USATI(usati_32, uint32_t, int32_t, uint32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 1U)
+GEN_PSIMD_SATI(sati_64, uint64_t, int64_t, int64_t,
+ EXTRACT64, INSERT64, ELEMS_D, 0x3f)
+GEN_PSIMD_USATI(usati_64, uint64_t, int64_t, uint64_t, uint64_t,
+ EXTRACT64, INSERT64, ELEMS_D, 1ULL)
+
diff --git a/target/riscv/tcg/translate.c b/target/riscv/tcg/translate.c
index 9684dbe7528..0df9d4190f1 100644
--- a/target/riscv/tcg/translate.c
+++ b/target/riscv/tcg/translate.c
@@ -103,6 +103,7 @@ typedef struct DisasContext {
bool vstart_eq_zero;
bool vl_eq_vlmax;
bool altfmt;
+ uint8_t p_vxsat_excp;
CPUState *cs;
TCGv zero;
/* actual address width */
@@ -1199,6 +1200,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
#include "insn_trans/trans_rvh.c.inc"
#include "insn_trans/trans_rvv.c.inc"
#include "insn_trans/trans_rvb.c.inc"
+#include "insn_trans/trans_rvp.c.inc"
#include "insn_trans/trans_rvzicond.c.inc"
#include "insn_trans/trans_rvzacas.c.inc"
#include "insn_trans/trans_rvzabha.c.inc"
@@ -1333,6 +1335,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->vstart_eq_zero = FIELD_EX32(tb_flags, TB_FLAGS, VSTART_EQ_ZERO);
ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
ctx->altfmt = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS, ALTFMT);
+ ctx->p_vxsat_excp = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS,
+ P_VXSAT_EXCP);
ctx->misa_mxl_max = mcc->def->misa_mxl_max;
ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL);
ctx->address_xl = FIELD_EX32(tb_flags, TB_FLAGS, AXL);
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions
2026-07-17 10:06 ` [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions Molly Chen
@ 2026-07-26 22:05 ` Daniel Henrique Barboza
2026-07-29 6:17 ` Nutty.Liu
2026-07-29 9:27 ` Chao Liu
2 siblings, 0 replies; 31+ messages in thread
From: Daniel Henrique Barboza @ 2026-07-26 22:05 UTC (permalink / raw)
To: Molly Chen, palmer, alistair.francis, liwei1518, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: qemu-riscv, qemu-devel
On 7/17/2026 7:06 AM, Molly Chen wrote:
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
> ---
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> target/riscv/helper.h | 41 ++
> target/riscv/insn32.decode | 63 +++
> target/riscv/tcg/insn_trans/trans_rvp.c.inc | 547 ++++++++++++++++++++
> target/riscv/tcg/psimd_helper.c | 114 ++++
> target/riscv/tcg/translate.c | 4 +
> 5 files changed, 769 insertions(+)
> create mode 100644 target/riscv/tcg/insn_trans/trans_rvp.c.inc
>
> diff --git a/target/riscv/helper.h b/target/riscv/helper.h
> index 542b7c264fc..eebb2febd95 100644
> --- a/target/riscv/helper.h
> +++ b/target/riscv/helper.h
> @@ -1358,3 +1358,44 @@ DEF_HELPER_1(ssamoswap_disabled, void, env)
>
> /* Zalrsc SC write probe */
> DEF_HELPER_FLAGS_3(sc_probe_write, TCG_CALL_NO_WG, void, env, tl, tl)
> +
> +/* Packed SIMD */
> +/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
> +DEF_HELPER_3(padd_b, tl, env, tl, tl)
> +DEF_HELPER_3(padd_h, tl, env, tl, tl)
> +DEF_HELPER_3(padd_w, i64, env, i64, i64)
> +DEF_HELPER_3(padd_bs, tl, env, tl, tl)
> +DEF_HELPER_3(padd_hs, tl, env, tl, tl)
> +DEF_HELPER_3(padd_ws, i64, env, i64, i64)
> +DEF_HELPER_3(psub_b, tl, env, tl, tl)
> +DEF_HELPER_3(psub_h, tl, env, tl, tl)
> +DEF_HELPER_3(psub_w, i64, env, i64, i64)
> +DEF_HELPER_3(psh1add_h, tl, env, tl, tl)
> +DEF_HELPER_3(psh1add_w, i64, env, i64, i64)
> +DEF_HELPER_3(pssh1sadd_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssh1sadd_w, i64, env, i64, i64)
> +DEF_HELPER_3(ssh1sadd, i32, env, i32, i32)
> +DEF_HELPER_3(psadd_b, tl, env, tl, tl)
> +DEF_HELPER_3(psadd_h, tl, env, tl, tl)
> +DEF_HELPER_3(psadd_w, i64, env, i64, i64)
> +DEF_HELPER_3(psaddu_b, tl, env, tl, tl)
> +DEF_HELPER_3(psaddu_h, tl, env, tl, tl)
> +DEF_HELPER_3(psaddu_w, i64, env, i64, i64)
> +DEF_HELPER_3(sadd, i32, env, i32, i32)
> +DEF_HELPER_3(saddu, i32, env, i32, i32)
> +DEF_HELPER_3(pssub_b, tl, env, tl, tl)
> +DEF_HELPER_3(pssub_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssub_w, i64, env, i64, i64)
> +DEF_HELPER_3(pssubu_b, tl, env, tl, tl)
> +DEF_HELPER_3(pssubu_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssubu_w, i64, env, i64, i64)
> +DEF_HELPER_3(ssub, i32, env, i32, i32)
> +DEF_HELPER_3(ssubu, i32, env, i32, i32)
> +DEF_HELPER_3(psati_h, tl, env, tl, tl)
> +DEF_HELPER_3(pusati_h, tl, env, tl, tl)
> +DEF_HELPER_3(psati_w, i64, env, i64, i64)
> +DEF_HELPER_3(pusati_w, i64, env, i64, i64)
> +DEF_HELPER_3(sati_32, i32, env, i32, i32)
> +DEF_HELPER_3(usati_32, i32, env, i32, i32)
> +DEF_HELPER_3(sati_64, i64, env, i64, i64)
> +DEF_HELPER_3(usati_64, i64, env, i64, i64)
> diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
> index 21272fdb504..8da13669d73 100644
> --- a/target/riscv/insn32.decode
> +++ b/target/riscv/insn32.decode
> @@ -40,6 +40,9 @@
> %imm_z6 26:1 15:5
> %imm_mop5 30:1 26:2 20:2
> %imm_mop3 30:1 26:2
> +%imm_p_ui16 20:4
> +%imm_p_ui32 20:5
> +%imm_p_ui64 20:6
>
> # Argument sets:
> &empty
> @@ -60,6 +63,7 @@
> &k_aes shamt rs2 rs1 rd
> &mop5 imm rd rs1
> &mop3 imm rd rs1 rs2
> +&p_ui imm rs1 rd
>
> # Formats 32:
> @r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd
> @@ -105,6 +109,10 @@
> @mop5 . . .. .. .... .. ..... ... ..... ....... &mop5 imm=%imm_mop5 %rd %rs1
> @mop3 . . .. .. . ..... ..... ... ..... ....... &mop3 imm=%imm_mop3 %rd %rs1 %rs2
>
> +@p_ui16 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui16 %rs1 %rd
> +@p_ui32 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui32 %rs1 %rd
> +@p_ui64 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui64 %rs1 %rd
> +
> # Formats 64:
> @sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd
>
> @@ -1084,3 +1092,58 @@ sb_aqrl 00111 . . ..... ..... 000 ..... 0101111 @atom_st
> sh_aqrl 00111 . . ..... ..... 001 ..... 0101111 @atom_st
> sw_aqrl 00111 . . ..... ..... 010 ..... 0101111 @atom_st
> sd_aqrl 00111 . . ..... ..... 011 ..... 0101111 @atom_st
> +
> +# *** P Experimental Extension Version v020 ***
> +# Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating)
> +padd_b 1000010 ..... ..... 000 ..... 0111011 @r
> +padd_h 1000000 ..... ..... 000 ..... 0111011 @r
> +padd_w 1000001 ..... ..... 000 ..... 0111011 @r
> +padd_bs 1001110 ..... ..... 010 ..... 0011011 @r
> +padd_hs 1001100 ..... ..... 010 ..... 0011011 @r
> +padd_ws 1001101 ..... ..... 010 ..... 0011011 @r
> +psub_b 1100010 ..... ..... 000 ..... 0111011 @r
> +psub_h 1100000 ..... ..... 000 ..... 0111011 @r
> +psub_w 1100001 ..... ..... 000 ..... 0111011 @r
> +psh1add_h 1010000 ..... ..... 010 ..... 0111011 @r
> +psh1add_w 1010001 ..... ..... 010 ..... 0111011 @r
> +pssh1sadd_h 1011000 ..... ..... 010 ..... 0111011 @r
> +{
> + ssh1sadd 1011001 ..... ..... 010 ..... 0111011 @r
> + pssh1sadd_w 1011001 ..... ..... 010 ..... 0111011 @r
> +}
> +psadd_b 1001010 ..... ..... 000 ..... 0111011 @r
> +psadd_h 1001000 ..... ..... 000 ..... 0111011 @r
> +{
> + sadd 1001001 ..... ..... 000 ..... 0111011 @r
> + psadd_w 1001001 ..... ..... 000 ..... 0111011 @r
> +}
> +psaddu_b 1011010 ..... ..... 000 ..... 0111011 @r
> +psaddu_h 1011000 ..... ..... 000 ..... 0111011 @r
> +{
> + saddu 1011001 ..... ..... 000 ..... 0111011 @r
> + psaddu_w 1011001 ..... ..... 000 ..... 0111011 @r
> +}
> +pssub_b 1101010 ..... ..... 000 ..... 0111011 @r
> +pssub_h 1101000 ..... ..... 000 ..... 0111011 @r
> +{
> + ssub 1101001 ..... ..... 000 ..... 0111011 @r
> + pssub_w 1101001 ..... ..... 000 ..... 0111011 @r
> +}
> +pssubu_b 1111010 ..... ..... 000 ..... 0111011 @r
> +pssubu_h 1111000 ..... ..... 000 ..... 0111011 @r
> +{
> + ssubu 1111001 ..... ..... 000 ..... 0111011 @r
> + pssubu_w 1111001 ..... ..... 000 ..... 0111011 @r
> +}
> +psati_h 11100 001.... ..... 100 ..... 0011011 @p_ui16
> +pusati_h 10100 001.... ..... 100 ..... 0011011 @p_ui16
> +{
> + sati_32 11100 01..... ..... 100 ..... 0011011 @p_ui32
> + psati_w 11100 01..... ..... 100 ..... 0011011 @p_ui32
> +}
> +{
> + usati_32 10100 01..... ..... 100 ..... 0011011 @p_ui32
> + pusati_w 10100 01..... ..... 100 ..... 0011011 @p_ui32
> +}
> +sati_64 111001 ...... ..... 100 ..... 0011011 @p_ui64
> +usati_64 101001 ...... ..... 100 ..... 0011011 @p_ui64
> diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> new file mode 100644
> index 00000000000..056ccfb486e
> --- /dev/null
> +++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> @@ -0,0 +1,547 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/* RISC-V translation routines for the P Standard Extensions. */
> +/* Copyright (c) 2026 ISRC ISCAS. */
> +
> +/* Save a 64 bit data in src to dst and dst + 1 */
> +
> +static bool require_rvp(DisasContext *ctx)
> +{
> + uint32_t opcode = ctx->opcode & 0x7f;
> +
> + if (!has_ext(ctx, RVP)) {
> + return false;
> + }
> +
> + /*
> + * P_VXSAT_EXCP is encoded in the TB flags only when P is implemented
> + * without Zve*, where stateen0.VXSAT controls the whole OP-32 and
> + * OP-IMM-32 P instruction spaces. When Zve* is present, this field
> + * remains NONE and vxsat access is checked by the VS path instead.
> + */
> + if ((opcode == 0x3b || opcode == 0x1b) &&
> + ctx->p_vxsat_excp != P_VXSAT_EXCP_NONE) {
> + ctx->virt_inst_excp =
> + ctx->p_vxsat_excp == P_VXSAT_EXCP_VIRTUAL;
> + return false;
> + }
> +
> + return true;
> +}
> +
> +static bool prepare_rvp_vxsat(DisasContext *ctx)
> +{
> + if (!ctx->cfg_ptr->ext_zve32x) {
> + return true;
> + }
> +
> + if (ctx->mstatus_vs == EXT_STATUS_DISABLED) {
> + return false;
> + }
> +
> + mark_vs_dirty(ctx);
> + return true;
> +}
> +
> +#define REQUIRE_RVP(ctx) do { \
> + if (!require_rvp(ctx)) { \
> + return false; \
> + } \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_BODY(NAME, VXSAT) \
> +do { \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
> + TCGv dest = dest_gpr(ctx, a->rd); \
> + gen_helper_##NAME(dest, tcg_env, src1, src2); \
> + gen_set_gpr(ctx, a->rd, dest); \
> + return true; \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_UNAVAILABLE_32(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_UNAVAILABLE_64(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_BODY(NAME, false); \
> +}
> +
> +#define GEN_SIMD_TRANS_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_BODY(NAME, true); \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_32(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + GEN_SIMD_TRANS_BODY(NAME, false); \
> +}
> +#define GEN_SIMD_TRANS_32_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + GEN_SIMD_TRANS_BODY(NAME, true); \
> +}
> +#else
> +#define GEN_SIMD_TRANS_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_64(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_BODY(NAME, false); \
> +}
> +#define GEN_SIMD_TRANS_64_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_BODY(NAME, true); \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_ACC_BODY(NAME, VXSAT) \
> +do { \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
> + TCGv dest = dest_gpr(ctx, a->rd); \
> + TCGv t = tcg_temp_new(); \
> + gen_helper_##NAME(t, tcg_env, src1, src2, dest); \
> + gen_set_gpr(ctx, a->rd, t); \
> + return true; \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_ACC(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_ACC_BODY(NAME, false); \
> +}
> +
> +#define GEN_SIMD_TRANS_ACC_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_ACC_BODY(NAME, true); \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_ACC_32(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + GEN_SIMD_TRANS_ACC_BODY(NAME, false); \
> +}
> +#else
> +#define GEN_SIMD_TRANS_ACC_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_ACC_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_ACC_64(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_ACC_BODY(NAME, false); \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_R1_BODY(NAME, VXSAT) \
> +do { \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv dest = dest_gpr(ctx, a->rd); \
> + gen_helper_##NAME(dest, tcg_env, src1); \
> + gen_set_gpr(ctx, a->rd, dest); \
> + return true; \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_R1(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_R1_BODY(NAME, false); \
> +}
> +
> +#define GEN_SIMD_TRANS_R1_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_R1_BODY(NAME, true); \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_R1_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_R1_64(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_R1_BODY(NAME, false); \
> +}
> +#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_R1_BODY(NAME, true); \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_IMM_BODY(NAME, VXSAT) \
> +do { \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv imm = tcg_constant_tl(a->imm); \
> + TCGv dest = dest_gpr(ctx, a->rd); \
> + gen_helper_##NAME(dest, tcg_env, src1, imm); \
> + gen_set_gpr(ctx, a->rd, dest); \
> + return true; \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_IMM(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, false); \
> +}
> +
> +#define GEN_SIMD_TRANS_IMM_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, true); \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_IMM_32(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, false); \
> +}
> +#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, true); \
> +}
> +#else
> +#define GEN_SIMD_TRANS_IMM_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_IMM_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_IMM_64(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, false); \
> +}
> +#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, true); \
> +}
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, SRC2) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + TCGv_i32 src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv_i32 src2 = SRC2; \
> + TCGv_i64 t = tcg_temp_new_i64(); \
> + gen_helper_##NAME(t, tcg_env, src1, src2); \
> + set_pair_regs(ctx, (a->rd) * 2, t); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) \
> + GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE))
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) \
> + GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, tcg_constant_i32(a->imm))
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, SRC2_0, SRC2_1, VXSAT) \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
> + TCGv src2_0 = SRC2_0; \
> + TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2); \
> + TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
> + TCGv src2_1 = SRC2_1; \
> + TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1); \
> + gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2_0); \
> + gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2_1); \
> + gen_set_gpr(ctx, (a->rd) * 2, dest_0); \
> + gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
> + get_gpr(ctx, (a->rs2) * 2, EXT_NONE), \
> + get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
> + get_gpr(ctx, (a->rs2) * 2, EXT_NONE), \
> + get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), true)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
> + tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
> + tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, VXSAT) \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
> + TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2); \
> + TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
> + TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1); \
> + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
> + gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2); \
> + gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2); \
> + gen_set_gpr(ctx, (a->rd) * 2, dest_0); \
> + gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, VXSAT) \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a) \
> +{ \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
> + TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2); \
> + TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
> + TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1); \
> + gen_helper_##HELPER(dest_0, tcg_env, src1_0); \
> + gen_helper_##HELPER(dest_1, tcg_env, src1_1); \
> + gen_set_gpr(ctx, (a->rd) * 2, dest_0); \
> + gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
> + TCGv_i64 t = tcg_temp_new_i64(); \
> + if (a->rd == 0) { \
> + tcg_gen_movi_i64(t, 0); \
> + } else { \
> + get_pair_regs(ctx, t, (a->rd) * 2); \
> + } \
> + gen_helper_##NAME(t, tcg_env, src1, src2, t); \
> + set_pair_regs(ctx, (a->rd) * 2, t); \
> + return true; \
> +}
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + TCGv_i32 src1_l; \
> + TCGv_i32 src1_h; \
> + TCGv_i32 src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
> + TCGv_i32 dest = dest_gpr(ctx, a->rd); \
> + if (a->rs1 == 0) { \
> + src1_l = tcg_temp_new_i32(); \
> + src1_h = tcg_temp_new_i32(); \
> + tcg_gen_movi_i32(src1_l, 0); \
> + tcg_gen_movi_i32(src1_h, 0); \
> + } else { \
> + src1_l = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
> + src1_h = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
> + } \
> + gen_helper_##NAME(dest, tcg_env, src1_l, src1_h, src2); \
> + gen_set_gpr(ctx, a->rd, dest); \
> + return true; \
> +}
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_PN_OP(NAME, SRC2, VXSAT) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv_i64 s1 = tcg_temp_new_i64(); \
> + if (a->rs1 == 0) { \
> + tcg_gen_mov_i64(s1, 0); \
> + } else { \
> + get_pair_regs(ctx, s1, a->rs1 * 2); \
> + } \
> + TCGv src2 = SRC2; \
> + TCGv dest = dest_gpr(ctx, a->rd); \
> + gen_helper_##NAME(dest, tcg_env, s1, src2); \
> + gen_set_gpr(ctx, a->rd, dest); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) \
> + GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), false)
> +
> +#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) \
> + GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), true)
> +
> +#define GEN_SIMD_TRANS_PN_OP_REG(NAME) \
> + GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), false)
> +
> +#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) \
> + GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), true)
> +#else
> +#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_REG(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
> +GEN_SIMD_TRANS(padd_b)
> +GEN_SIMD_TRANS(padd_h)
> +GEN_SIMD_TRANS_64(padd_w)
> +GEN_SIMD_TRANS(padd_bs)
> +GEN_SIMD_TRANS(padd_hs)
> +GEN_SIMD_TRANS_64(padd_ws)
> +GEN_SIMD_TRANS(psub_b)
> +GEN_SIMD_TRANS(psub_h)
> +GEN_SIMD_TRANS_64(psub_w)
> +GEN_SIMD_TRANS(psh1add_h)
> +GEN_SIMD_TRANS_64(psh1add_w)
> +GEN_SIMD_TRANS_VXSAT(pssh1sadd_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssh1sadd_w)
> +GEN_SIMD_TRANS_32_VXSAT(ssh1sadd)
> +GEN_SIMD_TRANS_VXSAT(psadd_b)
> +GEN_SIMD_TRANS_VXSAT(psadd_h)
> +GEN_SIMD_TRANS_64_VXSAT(psadd_w)
> +GEN_SIMD_TRANS_VXSAT(psaddu_b)
> +GEN_SIMD_TRANS_VXSAT(psaddu_h)
> +GEN_SIMD_TRANS_64_VXSAT(psaddu_w)
> +GEN_SIMD_TRANS_32_VXSAT(sadd)
> +GEN_SIMD_TRANS_32_VXSAT(saddu)
> +GEN_SIMD_TRANS_VXSAT(pssub_b)
> +GEN_SIMD_TRANS_VXSAT(pssub_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssub_w)
> +GEN_SIMD_TRANS_VXSAT(pssubu_b)
> +GEN_SIMD_TRANS_VXSAT(pssubu_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssubu_w)
> +GEN_SIMD_TRANS_32_VXSAT(ssub)
> +GEN_SIMD_TRANS_32_VXSAT(ssubu)
> +GEN_SIMD_TRANS_IMM_VXSAT(psati_h)
> +GEN_SIMD_TRANS_IMM_VXSAT(pusati_h)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(psati_w)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(pusati_w)
> +GEN_SIMD_TRANS_IMM_32_VXSAT(sati_32)
> +GEN_SIMD_TRANS_IMM_32_VXSAT(usati_32)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(sati_64)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(usati_64)
> +
> diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
> index 2948bbb2a86..52c58e0287e 100644
> --- a/target/riscv/tcg/psimd_helper.c
> +++ b/target/riscv/tcg/psimd_helper.c
> @@ -1654,3 +1654,117 @@ uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
>
> /* Basic addition operations (non-saturating) */
>
> +GEN_PSIMD_BINOP(padd_b, target_ulong, uint8_t, uint8_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP(padd_h, target_ulong, uint16_t, uint16_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP(padd_w, uint64_t, uint32_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +GEN_PSIMD_BINOP_SCALAR(padd_bs, target_ulong, uint8_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP_SCALAR(padd_hs, target_ulong, uint16_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP_SCALAR(padd_ws, uint64_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +/* Basic subtraction operations (non-saturating) */
> +
> +GEN_PSIMD_BINOP(psub_b, target_ulong, uint8_t, uint8_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
> +GEN_PSIMD_BINOP(psub_h, target_ulong, uint16_t, uint16_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
> +GEN_PSIMD_BINOP(psub_w, uint64_t, uint32_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
> +
> +/* Shift-left-by-one and add operations */
> +
> +GEN_PSIMD_SHADD(psh1add_h, target_ulong, uint16_t,
> + EXTRACT16, INSERT16, ELEMS_H, 1)
> +GEN_PSIMD_SHADD(psh1add_w, uint64_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W, 1)
> +
> +GEN_PSIMD_SAT_SHADD(pssh1sadd_h, target_ulong, int16_t, int32_t,
> + EXTRACT16, INSERT16, ELEMS_H, 1, -0x4000, 0x3fff,
> + SAT_MIN_H, SAT_MAX_H, signed_saturate_h)
> +GEN_PSIMD_SAT_SHADD(pssh1sadd_w, uint64_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
> + 0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
> +
> +GEN_PSIMD_SAT_SHADD(ssh1sadd, uint32_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
> + 0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
> +
> +/* Saturating addition operations */
> +
> +GEN_PSIMD_SAT_BINOP(psadd_b, target_ulong, int8_t, int32_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
> + signed_saturate_b)
> +GEN_PSIMD_SAT_BINOP(psadd_h, target_ulong, int16_t, int32_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
> + signed_saturate_h)
> +GEN_PSIMD_SAT_BINOP(psadd_w, uint64_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> + signed_saturate_w)
> +
> +GEN_PSIMD_SAT_BINOP(psaddu_b, target_ulong, uint8_t, uint32_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
> + unsigned_saturate_b)
> +GEN_PSIMD_SAT_BINOP(psaddu_h, target_ulong, uint16_t, uint32_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
> + unsigned_saturate_h)
> +GEN_PSIMD_SAT_BINOP(psaddu_w, uint64_t, uint32_t, uint64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> + unsigned_saturate_w)
> +
> +GEN_PSIMD_SAT_BINOP(sadd, uint32_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> + signed_saturate_w)
> +GEN_PSIMD_SAT_BINOP(saddu, uint32_t, uint32_t, uint64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> + unsigned_saturate_w)
> +
> +/* Saturating subtraction operations */
> +
> +GEN_PSIMD_SAT_BINOP(pssub_b, target_ulong, int8_t, int32_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB,
> + signed_saturate_b)
> +GEN_PSIMD_SAT_BINOP(pssub_h, target_ulong, int16_t, int32_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB,
> + signed_saturate_h)
> +GEN_PSIMD_SAT_BINOP(pssub_w, uint64_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
> + signed_saturate_w)
> +
> +GEN_PSIMD_USUB_SAT(pssubu_b, target_ulong, uint8_t,
> + EXTRACT8, INSERT8, ELEMS_B)
> +GEN_PSIMD_USUB_SAT(pssubu_h, target_ulong, uint16_t,
> + EXTRACT16, INSERT16, ELEMS_H)
> +GEN_PSIMD_USUB_SAT(pssubu_w, uint64_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W)
> +
> +GEN_PSIMD_SAT_BINOP(ssub, uint32_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
> + signed_saturate_w)
> +GEN_PSIMD_USUB_SAT(ssubu, uint32_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W)
> +
> +/* Saturation instructions (SAT, USAT) */
> +
> +GEN_PSIMD_SATI(psati_h, target_ulong, int16_t, int64_t,
> + EXTRACT16, INSERT16, ELEMS_H, 0x0f)
> +GEN_PSIMD_USATI(pusati_h, target_ulong, int16_t, uint16_t, uint32_t,
> + EXTRACT16, INSERT16, ELEMS_H, 1U)
> +GEN_PSIMD_SATI(psati_w, uint64_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, 0x1f)
> +GEN_PSIMD_USATI(pusati_w, uint64_t, int32_t, uint32_t, uint64_t,
> + EXTRACT32, INSERT32, ELEMS_W, 1ULL)
> +GEN_PSIMD_SATI(sati_32, uint32_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, 0x1f)
> +GEN_PSIMD_USATI(usati_32, uint32_t, int32_t, uint32_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W, 1U)
> +GEN_PSIMD_SATI(sati_64, uint64_t, int64_t, int64_t,
> + EXTRACT64, INSERT64, ELEMS_D, 0x3f)
> +GEN_PSIMD_USATI(usati_64, uint64_t, int64_t, uint64_t, uint64_t,
> + EXTRACT64, INSERT64, ELEMS_D, 1ULL)
> +
> diff --git a/target/riscv/tcg/translate.c b/target/riscv/tcg/translate.c
> index 9684dbe7528..0df9d4190f1 100644
> --- a/target/riscv/tcg/translate.c
> +++ b/target/riscv/tcg/translate.c
> @@ -103,6 +103,7 @@ typedef struct DisasContext {
> bool vstart_eq_zero;
> bool vl_eq_vlmax;
> bool altfmt;
> + uint8_t p_vxsat_excp;
> CPUState *cs;
> TCGv zero;
> /* actual address width */
> @@ -1199,6 +1200,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
> #include "insn_trans/trans_rvh.c.inc"
> #include "insn_trans/trans_rvv.c.inc"
> #include "insn_trans/trans_rvb.c.inc"
> +#include "insn_trans/trans_rvp.c.inc"
> #include "insn_trans/trans_rvzicond.c.inc"
> #include "insn_trans/trans_rvzacas.c.inc"
> #include "insn_trans/trans_rvzabha.c.inc"
> @@ -1333,6 +1335,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
> ctx->vstart_eq_zero = FIELD_EX32(tb_flags, TB_FLAGS, VSTART_EQ_ZERO);
> ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
> ctx->altfmt = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS, ALTFMT);
> + ctx->p_vxsat_excp = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS,
> + P_VXSAT_EXCP);
> ctx->misa_mxl_max = mcc->def->misa_mxl_max;
> ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL);
> ctx->address_xl = FIELD_EX32(tb_flags, TB_FLAGS, AXL);
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions
2026-07-17 10:06 ` [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions Molly Chen
2026-07-26 22:05 ` Daniel Henrique Barboza
@ 2026-07-29 6:17 ` Nutty.Liu
2026-07-29 9:27 ` Chao Liu
2 siblings, 0 replies; 31+ messages in thread
From: Nutty.Liu @ 2026-07-29 6:17 UTC (permalink / raw)
To: Molly Chen, palmer, alistair.francis, liwei1518, daniel.barboza,
zhiwei_liu, chao.liu.zevorn, Chao Liu
Cc: qemu-riscv, qemu-devel
On 7/17/2026 6:06 PM, Molly Chen wrote:
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Thanks,
Nutty
> ---
> target/riscv/helper.h | 41 ++
> target/riscv/insn32.decode | 63 +++
> target/riscv/tcg/insn_trans/trans_rvp.c.inc | 547 ++++++++++++++++++++
> target/riscv/tcg/psimd_helper.c | 114 ++++
> target/riscv/tcg/translate.c | 4 +
> 5 files changed, 769 insertions(+)
> create mode 100644 target/riscv/tcg/insn_trans/trans_rvp.c.inc
>
> diff --git a/target/riscv/helper.h b/target/riscv/helper.h
> index 542b7c264fc..eebb2febd95 100644
> --- a/target/riscv/helper.h
> +++ b/target/riscv/helper.h
> @@ -1358,3 +1358,44 @@ DEF_HELPER_1(ssamoswap_disabled, void, env)
>
> /* Zalrsc SC write probe */
> DEF_HELPER_FLAGS_3(sc_probe_write, TCG_CALL_NO_WG, void, env, tl, tl)
> +
> +/* Packed SIMD */
> +/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
> +DEF_HELPER_3(padd_b, tl, env, tl, tl)
> +DEF_HELPER_3(padd_h, tl, env, tl, tl)
> +DEF_HELPER_3(padd_w, i64, env, i64, i64)
> +DEF_HELPER_3(padd_bs, tl, env, tl, tl)
> +DEF_HELPER_3(padd_hs, tl, env, tl, tl)
> +DEF_HELPER_3(padd_ws, i64, env, i64, i64)
> +DEF_HELPER_3(psub_b, tl, env, tl, tl)
> +DEF_HELPER_3(psub_h, tl, env, tl, tl)
> +DEF_HELPER_3(psub_w, i64, env, i64, i64)
> +DEF_HELPER_3(psh1add_h, tl, env, tl, tl)
> +DEF_HELPER_3(psh1add_w, i64, env, i64, i64)
> +DEF_HELPER_3(pssh1sadd_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssh1sadd_w, i64, env, i64, i64)
> +DEF_HELPER_3(ssh1sadd, i32, env, i32, i32)
> +DEF_HELPER_3(psadd_b, tl, env, tl, tl)
> +DEF_HELPER_3(psadd_h, tl, env, tl, tl)
> +DEF_HELPER_3(psadd_w, i64, env, i64, i64)
> +DEF_HELPER_3(psaddu_b, tl, env, tl, tl)
> +DEF_HELPER_3(psaddu_h, tl, env, tl, tl)
> +DEF_HELPER_3(psaddu_w, i64, env, i64, i64)
> +DEF_HELPER_3(sadd, i32, env, i32, i32)
> +DEF_HELPER_3(saddu, i32, env, i32, i32)
> +DEF_HELPER_3(pssub_b, tl, env, tl, tl)
> +DEF_HELPER_3(pssub_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssub_w, i64, env, i64, i64)
> +DEF_HELPER_3(pssubu_b, tl, env, tl, tl)
> +DEF_HELPER_3(pssubu_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssubu_w, i64, env, i64, i64)
> +DEF_HELPER_3(ssub, i32, env, i32, i32)
> +DEF_HELPER_3(ssubu, i32, env, i32, i32)
> +DEF_HELPER_3(psati_h, tl, env, tl, tl)
> +DEF_HELPER_3(pusati_h, tl, env, tl, tl)
> +DEF_HELPER_3(psati_w, i64, env, i64, i64)
> +DEF_HELPER_3(pusati_w, i64, env, i64, i64)
> +DEF_HELPER_3(sati_32, i32, env, i32, i32)
> +DEF_HELPER_3(usati_32, i32, env, i32, i32)
> +DEF_HELPER_3(sati_64, i64, env, i64, i64)
> +DEF_HELPER_3(usati_64, i64, env, i64, i64)
> diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
> index 21272fdb504..8da13669d73 100644
> --- a/target/riscv/insn32.decode
> +++ b/target/riscv/insn32.decode
> @@ -40,6 +40,9 @@
> %imm_z6 26:1 15:5
> %imm_mop5 30:1 26:2 20:2
> %imm_mop3 30:1 26:2
> +%imm_p_ui16 20:4
> +%imm_p_ui32 20:5
> +%imm_p_ui64 20:6
>
> # Argument sets:
> &empty
> @@ -60,6 +63,7 @@
> &k_aes shamt rs2 rs1 rd
> &mop5 imm rd rs1
> &mop3 imm rd rs1 rs2
> +&p_ui imm rs1 rd
>
> # Formats 32:
> @r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd
> @@ -105,6 +109,10 @@
> @mop5 . . .. .. .... .. ..... ... ..... ....... &mop5 imm=%imm_mop5 %rd %rs1
> @mop3 . . .. .. . ..... ..... ... ..... ....... &mop3 imm=%imm_mop3 %rd %rs1 %rs2
>
> +@p_ui16 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui16 %rs1 %rd
> +@p_ui32 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui32 %rs1 %rd
> +@p_ui64 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui64 %rs1 %rd
> +
> # Formats 64:
> @sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd
>
> @@ -1084,3 +1092,58 @@ sb_aqrl 00111 . . ..... ..... 000 ..... 0101111 @atom_st
> sh_aqrl 00111 . . ..... ..... 001 ..... 0101111 @atom_st
> sw_aqrl 00111 . . ..... ..... 010 ..... 0101111 @atom_st
> sd_aqrl 00111 . . ..... ..... 011 ..... 0101111 @atom_st
> +
> +# *** P Experimental Extension Version v020 ***
> +# Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating)
> +padd_b 1000010 ..... ..... 000 ..... 0111011 @r
> +padd_h 1000000 ..... ..... 000 ..... 0111011 @r
> +padd_w 1000001 ..... ..... 000 ..... 0111011 @r
> +padd_bs 1001110 ..... ..... 010 ..... 0011011 @r
> +padd_hs 1001100 ..... ..... 010 ..... 0011011 @r
> +padd_ws 1001101 ..... ..... 010 ..... 0011011 @r
> +psub_b 1100010 ..... ..... 000 ..... 0111011 @r
> +psub_h 1100000 ..... ..... 000 ..... 0111011 @r
> +psub_w 1100001 ..... ..... 000 ..... 0111011 @r
> +psh1add_h 1010000 ..... ..... 010 ..... 0111011 @r
> +psh1add_w 1010001 ..... ..... 010 ..... 0111011 @r
> +pssh1sadd_h 1011000 ..... ..... 010 ..... 0111011 @r
> +{
> + ssh1sadd 1011001 ..... ..... 010 ..... 0111011 @r
> + pssh1sadd_w 1011001 ..... ..... 010 ..... 0111011 @r
> +}
> +psadd_b 1001010 ..... ..... 000 ..... 0111011 @r
> +psadd_h 1001000 ..... ..... 000 ..... 0111011 @r
> +{
> + sadd 1001001 ..... ..... 000 ..... 0111011 @r
> + psadd_w 1001001 ..... ..... 000 ..... 0111011 @r
> +}
> +psaddu_b 1011010 ..... ..... 000 ..... 0111011 @r
> +psaddu_h 1011000 ..... ..... 000 ..... 0111011 @r
> +{
> + saddu 1011001 ..... ..... 000 ..... 0111011 @r
> + psaddu_w 1011001 ..... ..... 000 ..... 0111011 @r
> +}
> +pssub_b 1101010 ..... ..... 000 ..... 0111011 @r
> +pssub_h 1101000 ..... ..... 000 ..... 0111011 @r
> +{
> + ssub 1101001 ..... ..... 000 ..... 0111011 @r
> + pssub_w 1101001 ..... ..... 000 ..... 0111011 @r
> +}
> +pssubu_b 1111010 ..... ..... 000 ..... 0111011 @r
> +pssubu_h 1111000 ..... ..... 000 ..... 0111011 @r
> +{
> + ssubu 1111001 ..... ..... 000 ..... 0111011 @r
> + pssubu_w 1111001 ..... ..... 000 ..... 0111011 @r
> +}
> +psati_h 11100 001.... ..... 100 ..... 0011011 @p_ui16
> +pusati_h 10100 001.... ..... 100 ..... 0011011 @p_ui16
> +{
> + sati_32 11100 01..... ..... 100 ..... 0011011 @p_ui32
> + psati_w 11100 01..... ..... 100 ..... 0011011 @p_ui32
> +}
> +{
> + usati_32 10100 01..... ..... 100 ..... 0011011 @p_ui32
> + pusati_w 10100 01..... ..... 100 ..... 0011011 @p_ui32
> +}
> +sati_64 111001 ...... ..... 100 ..... 0011011 @p_ui64
> +usati_64 101001 ...... ..... 100 ..... 0011011 @p_ui64
> diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> new file mode 100644
> index 00000000000..056ccfb486e
> --- /dev/null
> +++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> @@ -0,0 +1,547 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/* RISC-V translation routines for the P Standard Extensions. */
> +/* Copyright (c) 2026 ISRC ISCAS. */
> +
> +/* Save a 64 bit data in src to dst and dst + 1 */
> +
> +static bool require_rvp(DisasContext *ctx)
> +{
> + uint32_t opcode = ctx->opcode & 0x7f;
> +
> + if (!has_ext(ctx, RVP)) {
> + return false;
> + }
> +
> + /*
> + * P_VXSAT_EXCP is encoded in the TB flags only when P is implemented
> + * without Zve*, where stateen0.VXSAT controls the whole OP-32 and
> + * OP-IMM-32 P instruction spaces. When Zve* is present, this field
> + * remains NONE and vxsat access is checked by the VS path instead.
> + */
> + if ((opcode == 0x3b || opcode == 0x1b) &&
> + ctx->p_vxsat_excp != P_VXSAT_EXCP_NONE) {
> + ctx->virt_inst_excp =
> + ctx->p_vxsat_excp == P_VXSAT_EXCP_VIRTUAL;
> + return false;
> + }
> +
> + return true;
> +}
> +
> +static bool prepare_rvp_vxsat(DisasContext *ctx)
> +{
> + if (!ctx->cfg_ptr->ext_zve32x) {
> + return true;
> + }
> +
> + if (ctx->mstatus_vs == EXT_STATUS_DISABLED) {
> + return false;
> + }
> +
> + mark_vs_dirty(ctx);
> + return true;
> +}
> +
> +#define REQUIRE_RVP(ctx) do { \
> + if (!require_rvp(ctx)) { \
> + return false; \
> + } \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_BODY(NAME, VXSAT) \
> +do { \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
> + TCGv dest = dest_gpr(ctx, a->rd); \
> + gen_helper_##NAME(dest, tcg_env, src1, src2); \
> + gen_set_gpr(ctx, a->rd, dest); \
> + return true; \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_UNAVAILABLE_32(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_UNAVAILABLE_64(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_BODY(NAME, false); \
> +}
> +
> +#define GEN_SIMD_TRANS_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_BODY(NAME, true); \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_32(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + GEN_SIMD_TRANS_BODY(NAME, false); \
> +}
> +#define GEN_SIMD_TRANS_32_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + GEN_SIMD_TRANS_BODY(NAME, true); \
> +}
> +#else
> +#define GEN_SIMD_TRANS_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_64(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_BODY(NAME, false); \
> +}
> +#define GEN_SIMD_TRANS_64_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_BODY(NAME, true); \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_ACC_BODY(NAME, VXSAT) \
> +do { \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
> + TCGv dest = dest_gpr(ctx, a->rd); \
> + TCGv t = tcg_temp_new(); \
> + gen_helper_##NAME(t, tcg_env, src1, src2, dest); \
> + gen_set_gpr(ctx, a->rd, t); \
> + return true; \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_ACC(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_ACC_BODY(NAME, false); \
> +}
> +
> +#define GEN_SIMD_TRANS_ACC_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_ACC_BODY(NAME, true); \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_ACC_32(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + GEN_SIMD_TRANS_ACC_BODY(NAME, false); \
> +}
> +#else
> +#define GEN_SIMD_TRANS_ACC_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_ACC_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_ACC_64(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_ACC_BODY(NAME, false); \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_R1_BODY(NAME, VXSAT) \
> +do { \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv dest = dest_gpr(ctx, a->rd); \
> + gen_helper_##NAME(dest, tcg_env, src1); \
> + gen_set_gpr(ctx, a->rd, dest); \
> + return true; \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_R1(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_R1_BODY(NAME, false); \
> +}
> +
> +#define GEN_SIMD_TRANS_R1_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_R1_BODY(NAME, true); \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_R1_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_R1_64(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_R1_BODY(NAME, false); \
> +}
> +#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_R1_BODY(NAME, true); \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_IMM_BODY(NAME, VXSAT) \
> +do { \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv imm = tcg_constant_tl(a->imm); \
> + TCGv dest = dest_gpr(ctx, a->rd); \
> + gen_helper_##NAME(dest, tcg_env, src1, imm); \
> + gen_set_gpr(ctx, a->rd, dest); \
> + return true; \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_IMM(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, false); \
> +}
> +
> +#define GEN_SIMD_TRANS_IMM_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, true); \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_IMM_32(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, false); \
> +}
> +#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, true); \
> +}
> +#else
> +#define GEN_SIMD_TRANS_IMM_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_IMM_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_IMM_64(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, false); \
> +}
> +#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, true); \
> +}
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, SRC2) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + TCGv_i32 src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv_i32 src2 = SRC2; \
> + TCGv_i64 t = tcg_temp_new_i64(); \
> + gen_helper_##NAME(t, tcg_env, src1, src2); \
> + set_pair_regs(ctx, (a->rd) * 2, t); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) \
> + GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE))
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) \
> + GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, tcg_constant_i32(a->imm))
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, SRC2_0, SRC2_1, VXSAT) \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
> + TCGv src2_0 = SRC2_0; \
> + TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2); \
> + TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
> + TCGv src2_1 = SRC2_1; \
> + TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1); \
> + gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2_0); \
> + gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2_1); \
> + gen_set_gpr(ctx, (a->rd) * 2, dest_0); \
> + gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
> + get_gpr(ctx, (a->rs2) * 2, EXT_NONE), \
> + get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
> + get_gpr(ctx, (a->rs2) * 2, EXT_NONE), \
> + get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), true)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
> + tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
> + tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, VXSAT) \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
> + TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2); \
> + TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
> + TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1); \
> + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
> + gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2); \
> + gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2); \
> + gen_set_gpr(ctx, (a->rd) * 2, dest_0); \
> + gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, VXSAT) \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a) \
> +{ \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
> + TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2); \
> + TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
> + TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1); \
> + gen_helper_##HELPER(dest_0, tcg_env, src1_0); \
> + gen_helper_##HELPER(dest_1, tcg_env, src1_1); \
> + gen_set_gpr(ctx, (a->rd) * 2, dest_0); \
> + gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
> + TCGv_i64 t = tcg_temp_new_i64(); \
> + if (a->rd == 0) { \
> + tcg_gen_movi_i64(t, 0); \
> + } else { \
> + get_pair_regs(ctx, t, (a->rd) * 2); \
> + } \
> + gen_helper_##NAME(t, tcg_env, src1, src2, t); \
> + set_pair_regs(ctx, (a->rd) * 2, t); \
> + return true; \
> +}
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + TCGv_i32 src1_l; \
> + TCGv_i32 src1_h; \
> + TCGv_i32 src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
> + TCGv_i32 dest = dest_gpr(ctx, a->rd); \
> + if (a->rs1 == 0) { \
> + src1_l = tcg_temp_new_i32(); \
> + src1_h = tcg_temp_new_i32(); \
> + tcg_gen_movi_i32(src1_l, 0); \
> + tcg_gen_movi_i32(src1_h, 0); \
> + } else { \
> + src1_l = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
> + src1_h = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
> + } \
> + gen_helper_##NAME(dest, tcg_env, src1_l, src1_h, src2); \
> + gen_set_gpr(ctx, a->rd, dest); \
> + return true; \
> +}
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_PN_OP(NAME, SRC2, VXSAT) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv_i64 s1 = tcg_temp_new_i64(); \
> + if (a->rs1 == 0) { \
> + tcg_gen_mov_i64(s1, 0); \
> + } else { \
> + get_pair_regs(ctx, s1, a->rs1 * 2); \
> + } \
> + TCGv src2 = SRC2; \
> + TCGv dest = dest_gpr(ctx, a->rd); \
> + gen_helper_##NAME(dest, tcg_env, s1, src2); \
> + gen_set_gpr(ctx, a->rd, dest); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) \
> + GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), false)
> +
> +#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) \
> + GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), true)
> +
> +#define GEN_SIMD_TRANS_PN_OP_REG(NAME) \
> + GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), false)
> +
> +#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) \
> + GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), true)
> +#else
> +#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_REG(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
> +GEN_SIMD_TRANS(padd_b)
> +GEN_SIMD_TRANS(padd_h)
> +GEN_SIMD_TRANS_64(padd_w)
> +GEN_SIMD_TRANS(padd_bs)
> +GEN_SIMD_TRANS(padd_hs)
> +GEN_SIMD_TRANS_64(padd_ws)
> +GEN_SIMD_TRANS(psub_b)
> +GEN_SIMD_TRANS(psub_h)
> +GEN_SIMD_TRANS_64(psub_w)
> +GEN_SIMD_TRANS(psh1add_h)
> +GEN_SIMD_TRANS_64(psh1add_w)
> +GEN_SIMD_TRANS_VXSAT(pssh1sadd_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssh1sadd_w)
> +GEN_SIMD_TRANS_32_VXSAT(ssh1sadd)
> +GEN_SIMD_TRANS_VXSAT(psadd_b)
> +GEN_SIMD_TRANS_VXSAT(psadd_h)
> +GEN_SIMD_TRANS_64_VXSAT(psadd_w)
> +GEN_SIMD_TRANS_VXSAT(psaddu_b)
> +GEN_SIMD_TRANS_VXSAT(psaddu_h)
> +GEN_SIMD_TRANS_64_VXSAT(psaddu_w)
> +GEN_SIMD_TRANS_32_VXSAT(sadd)
> +GEN_SIMD_TRANS_32_VXSAT(saddu)
> +GEN_SIMD_TRANS_VXSAT(pssub_b)
> +GEN_SIMD_TRANS_VXSAT(pssub_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssub_w)
> +GEN_SIMD_TRANS_VXSAT(pssubu_b)
> +GEN_SIMD_TRANS_VXSAT(pssubu_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssubu_w)
> +GEN_SIMD_TRANS_32_VXSAT(ssub)
> +GEN_SIMD_TRANS_32_VXSAT(ssubu)
> +GEN_SIMD_TRANS_IMM_VXSAT(psati_h)
> +GEN_SIMD_TRANS_IMM_VXSAT(pusati_h)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(psati_w)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(pusati_w)
> +GEN_SIMD_TRANS_IMM_32_VXSAT(sati_32)
> +GEN_SIMD_TRANS_IMM_32_VXSAT(usati_32)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(sati_64)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(usati_64)
> +
> diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
> index 2948bbb2a86..52c58e0287e 100644
> --- a/target/riscv/tcg/psimd_helper.c
> +++ b/target/riscv/tcg/psimd_helper.c
> @@ -1654,3 +1654,117 @@ uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
>
> /* Basic addition operations (non-saturating) */
>
> +GEN_PSIMD_BINOP(padd_b, target_ulong, uint8_t, uint8_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP(padd_h, target_ulong, uint16_t, uint16_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP(padd_w, uint64_t, uint32_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +GEN_PSIMD_BINOP_SCALAR(padd_bs, target_ulong, uint8_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP_SCALAR(padd_hs, target_ulong, uint16_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP_SCALAR(padd_ws, uint64_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +/* Basic subtraction operations (non-saturating) */
> +
> +GEN_PSIMD_BINOP(psub_b, target_ulong, uint8_t, uint8_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
> +GEN_PSIMD_BINOP(psub_h, target_ulong, uint16_t, uint16_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
> +GEN_PSIMD_BINOP(psub_w, uint64_t, uint32_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
> +
> +/* Shift-left-by-one and add operations */
> +
> +GEN_PSIMD_SHADD(psh1add_h, target_ulong, uint16_t,
> + EXTRACT16, INSERT16, ELEMS_H, 1)
> +GEN_PSIMD_SHADD(psh1add_w, uint64_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W, 1)
> +
> +GEN_PSIMD_SAT_SHADD(pssh1sadd_h, target_ulong, int16_t, int32_t,
> + EXTRACT16, INSERT16, ELEMS_H, 1, -0x4000, 0x3fff,
> + SAT_MIN_H, SAT_MAX_H, signed_saturate_h)
> +GEN_PSIMD_SAT_SHADD(pssh1sadd_w, uint64_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
> + 0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
> +
> +GEN_PSIMD_SAT_SHADD(ssh1sadd, uint32_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
> + 0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
> +
> +/* Saturating addition operations */
> +
> +GEN_PSIMD_SAT_BINOP(psadd_b, target_ulong, int8_t, int32_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
> + signed_saturate_b)
> +GEN_PSIMD_SAT_BINOP(psadd_h, target_ulong, int16_t, int32_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
> + signed_saturate_h)
> +GEN_PSIMD_SAT_BINOP(psadd_w, uint64_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> + signed_saturate_w)
> +
> +GEN_PSIMD_SAT_BINOP(psaddu_b, target_ulong, uint8_t, uint32_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
> + unsigned_saturate_b)
> +GEN_PSIMD_SAT_BINOP(psaddu_h, target_ulong, uint16_t, uint32_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
> + unsigned_saturate_h)
> +GEN_PSIMD_SAT_BINOP(psaddu_w, uint64_t, uint32_t, uint64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> + unsigned_saturate_w)
> +
> +GEN_PSIMD_SAT_BINOP(sadd, uint32_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> + signed_saturate_w)
> +GEN_PSIMD_SAT_BINOP(saddu, uint32_t, uint32_t, uint64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> + unsigned_saturate_w)
> +
> +/* Saturating subtraction operations */
> +
> +GEN_PSIMD_SAT_BINOP(pssub_b, target_ulong, int8_t, int32_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB,
> + signed_saturate_b)
> +GEN_PSIMD_SAT_BINOP(pssub_h, target_ulong, int16_t, int32_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB,
> + signed_saturate_h)
> +GEN_PSIMD_SAT_BINOP(pssub_w, uint64_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
> + signed_saturate_w)
> +
> +GEN_PSIMD_USUB_SAT(pssubu_b, target_ulong, uint8_t,
> + EXTRACT8, INSERT8, ELEMS_B)
> +GEN_PSIMD_USUB_SAT(pssubu_h, target_ulong, uint16_t,
> + EXTRACT16, INSERT16, ELEMS_H)
> +GEN_PSIMD_USUB_SAT(pssubu_w, uint64_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W)
> +
> +GEN_PSIMD_SAT_BINOP(ssub, uint32_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
> + signed_saturate_w)
> +GEN_PSIMD_USUB_SAT(ssubu, uint32_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W)
> +
> +/* Saturation instructions (SAT, USAT) */
> +
> +GEN_PSIMD_SATI(psati_h, target_ulong, int16_t, int64_t,
> + EXTRACT16, INSERT16, ELEMS_H, 0x0f)
> +GEN_PSIMD_USATI(pusati_h, target_ulong, int16_t, uint16_t, uint32_t,
> + EXTRACT16, INSERT16, ELEMS_H, 1U)
> +GEN_PSIMD_SATI(psati_w, uint64_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, 0x1f)
> +GEN_PSIMD_USATI(pusati_w, uint64_t, int32_t, uint32_t, uint64_t,
> + EXTRACT32, INSERT32, ELEMS_W, 1ULL)
> +GEN_PSIMD_SATI(sati_32, uint32_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, 0x1f)
> +GEN_PSIMD_USATI(usati_32, uint32_t, int32_t, uint32_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W, 1U)
> +GEN_PSIMD_SATI(sati_64, uint64_t, int64_t, int64_t,
> + EXTRACT64, INSERT64, ELEMS_D, 0x3f)
> +GEN_PSIMD_USATI(usati_64, uint64_t, int64_t, uint64_t, uint64_t,
> + EXTRACT64, INSERT64, ELEMS_D, 1ULL)
> +
> diff --git a/target/riscv/tcg/translate.c b/target/riscv/tcg/translate.c
> index 9684dbe7528..0df9d4190f1 100644
> --- a/target/riscv/tcg/translate.c
> +++ b/target/riscv/tcg/translate.c
> @@ -103,6 +103,7 @@ typedef struct DisasContext {
> bool vstart_eq_zero;
> bool vl_eq_vlmax;
> bool altfmt;
> + uint8_t p_vxsat_excp;
> CPUState *cs;
> TCGv zero;
> /* actual address width */
> @@ -1199,6 +1200,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
> #include "insn_trans/trans_rvh.c.inc"
> #include "insn_trans/trans_rvv.c.inc"
> #include "insn_trans/trans_rvb.c.inc"
> +#include "insn_trans/trans_rvp.c.inc"
> #include "insn_trans/trans_rvzicond.c.inc"
> #include "insn_trans/trans_rvzacas.c.inc"
> #include "insn_trans/trans_rvzabha.c.inc"
> @@ -1333,6 +1335,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
> ctx->vstart_eq_zero = FIELD_EX32(tb_flags, TB_FLAGS, VSTART_EQ_ZERO);
> ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
> ctx->altfmt = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS, ALTFMT);
> + ctx->p_vxsat_excp = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS,
> + P_VXSAT_EXCP);
> ctx->misa_mxl_max = mcc->def->misa_mxl_max;
> ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL);
> ctx->address_xl = FIELD_EX32(tb_flags, TB_FLAGS, AXL);
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions
2026-07-17 10:06 ` [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions Molly Chen
2026-07-26 22:05 ` Daniel Henrique Barboza
2026-07-29 6:17 ` Nutty.Liu
@ 2026-07-29 9:27 ` Chao Liu
2 siblings, 0 replies; 31+ messages in thread
From: Chao Liu @ 2026-07-29 9:27 UTC (permalink / raw)
To: Molly Chen
Cc: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
Chao Liu, qemu-riscv, qemu-devel
On Fri, Jul 17, 2026 at 10:06:56AM +0800, Molly Chen wrote:
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
I think we need to add a commit body to explain what the patch does.
Thanks,
Chao
> ---
> target/riscv/helper.h | 41 ++
> target/riscv/insn32.decode | 63 +++
> target/riscv/tcg/insn_trans/trans_rvp.c.inc | 547 ++++++++++++++++++++
> target/riscv/tcg/psimd_helper.c | 114 ++++
> target/riscv/tcg/translate.c | 4 +
> 5 files changed, 769 insertions(+)
> create mode 100644 target/riscv/tcg/insn_trans/trans_rvp.c.inc
>
> diff --git a/target/riscv/helper.h b/target/riscv/helper.h
> index 542b7c264fc..eebb2febd95 100644
> --- a/target/riscv/helper.h
> +++ b/target/riscv/helper.h
> @@ -1358,3 +1358,44 @@ DEF_HELPER_1(ssamoswap_disabled, void, env)
>
> /* Zalrsc SC write probe */
> DEF_HELPER_FLAGS_3(sc_probe_write, TCG_CALL_NO_WG, void, env, tl, tl)
> +
> +/* Packed SIMD */
> +/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
> +DEF_HELPER_3(padd_b, tl, env, tl, tl)
> +DEF_HELPER_3(padd_h, tl, env, tl, tl)
> +DEF_HELPER_3(padd_w, i64, env, i64, i64)
> +DEF_HELPER_3(padd_bs, tl, env, tl, tl)
> +DEF_HELPER_3(padd_hs, tl, env, tl, tl)
> +DEF_HELPER_3(padd_ws, i64, env, i64, i64)
> +DEF_HELPER_3(psub_b, tl, env, tl, tl)
> +DEF_HELPER_3(psub_h, tl, env, tl, tl)
> +DEF_HELPER_3(psub_w, i64, env, i64, i64)
> +DEF_HELPER_3(psh1add_h, tl, env, tl, tl)
> +DEF_HELPER_3(psh1add_w, i64, env, i64, i64)
> +DEF_HELPER_3(pssh1sadd_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssh1sadd_w, i64, env, i64, i64)
> +DEF_HELPER_3(ssh1sadd, i32, env, i32, i32)
> +DEF_HELPER_3(psadd_b, tl, env, tl, tl)
> +DEF_HELPER_3(psadd_h, tl, env, tl, tl)
> +DEF_HELPER_3(psadd_w, i64, env, i64, i64)
> +DEF_HELPER_3(psaddu_b, tl, env, tl, tl)
> +DEF_HELPER_3(psaddu_h, tl, env, tl, tl)
> +DEF_HELPER_3(psaddu_w, i64, env, i64, i64)
> +DEF_HELPER_3(sadd, i32, env, i32, i32)
> +DEF_HELPER_3(saddu, i32, env, i32, i32)
> +DEF_HELPER_3(pssub_b, tl, env, tl, tl)
> +DEF_HELPER_3(pssub_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssub_w, i64, env, i64, i64)
> +DEF_HELPER_3(pssubu_b, tl, env, tl, tl)
> +DEF_HELPER_3(pssubu_h, tl, env, tl, tl)
> +DEF_HELPER_3(pssubu_w, i64, env, i64, i64)
> +DEF_HELPER_3(ssub, i32, env, i32, i32)
> +DEF_HELPER_3(ssubu, i32, env, i32, i32)
> +DEF_HELPER_3(psati_h, tl, env, tl, tl)
> +DEF_HELPER_3(pusati_h, tl, env, tl, tl)
> +DEF_HELPER_3(psati_w, i64, env, i64, i64)
> +DEF_HELPER_3(pusati_w, i64, env, i64, i64)
> +DEF_HELPER_3(sati_32, i32, env, i32, i32)
> +DEF_HELPER_3(usati_32, i32, env, i32, i32)
> +DEF_HELPER_3(sati_64, i64, env, i64, i64)
> +DEF_HELPER_3(usati_64, i64, env, i64, i64)
> diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
> index 21272fdb504..8da13669d73 100644
> --- a/target/riscv/insn32.decode
> +++ b/target/riscv/insn32.decode
> @@ -40,6 +40,9 @@
> %imm_z6 26:1 15:5
> %imm_mop5 30:1 26:2 20:2
> %imm_mop3 30:1 26:2
> +%imm_p_ui16 20:4
> +%imm_p_ui32 20:5
> +%imm_p_ui64 20:6
>
> # Argument sets:
> &empty
> @@ -60,6 +63,7 @@
> &k_aes shamt rs2 rs1 rd
> &mop5 imm rd rs1
> &mop3 imm rd rs1 rs2
> +&p_ui imm rs1 rd
>
> # Formats 32:
> @r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd
> @@ -105,6 +109,10 @@
> @mop5 . . .. .. .... .. ..... ... ..... ....... &mop5 imm=%imm_mop5 %rd %rs1
> @mop3 . . .. .. . ..... ..... ... ..... ....... &mop3 imm=%imm_mop3 %rd %rs1 %rs2
>
> +@p_ui16 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui16 %rs1 %rd
> +@p_ui32 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui32 %rs1 %rd
> +@p_ui64 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui64 %rs1 %rd
> +
> # Formats 64:
> @sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd
>
> @@ -1084,3 +1092,58 @@ sb_aqrl 00111 . . ..... ..... 000 ..... 0101111 @atom_st
> sh_aqrl 00111 . . ..... ..... 001 ..... 0101111 @atom_st
> sw_aqrl 00111 . . ..... ..... 010 ..... 0101111 @atom_st
> sd_aqrl 00111 . . ..... ..... 011 ..... 0101111 @atom_st
> +
> +# *** P Experimental Extension Version v020 ***
> +# Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating)
> +padd_b 1000010 ..... ..... 000 ..... 0111011 @r
> +padd_h 1000000 ..... ..... 000 ..... 0111011 @r
> +padd_w 1000001 ..... ..... 000 ..... 0111011 @r
> +padd_bs 1001110 ..... ..... 010 ..... 0011011 @r
> +padd_hs 1001100 ..... ..... 010 ..... 0011011 @r
> +padd_ws 1001101 ..... ..... 010 ..... 0011011 @r
> +psub_b 1100010 ..... ..... 000 ..... 0111011 @r
> +psub_h 1100000 ..... ..... 000 ..... 0111011 @r
> +psub_w 1100001 ..... ..... 000 ..... 0111011 @r
> +psh1add_h 1010000 ..... ..... 010 ..... 0111011 @r
> +psh1add_w 1010001 ..... ..... 010 ..... 0111011 @r
> +pssh1sadd_h 1011000 ..... ..... 010 ..... 0111011 @r
> +{
> + ssh1sadd 1011001 ..... ..... 010 ..... 0111011 @r
> + pssh1sadd_w 1011001 ..... ..... 010 ..... 0111011 @r
> +}
> +psadd_b 1001010 ..... ..... 000 ..... 0111011 @r
> +psadd_h 1001000 ..... ..... 000 ..... 0111011 @r
> +{
> + sadd 1001001 ..... ..... 000 ..... 0111011 @r
> + psadd_w 1001001 ..... ..... 000 ..... 0111011 @r
> +}
> +psaddu_b 1011010 ..... ..... 000 ..... 0111011 @r
> +psaddu_h 1011000 ..... ..... 000 ..... 0111011 @r
> +{
> + saddu 1011001 ..... ..... 000 ..... 0111011 @r
> + psaddu_w 1011001 ..... ..... 000 ..... 0111011 @r
> +}
> +pssub_b 1101010 ..... ..... 000 ..... 0111011 @r
> +pssub_h 1101000 ..... ..... 000 ..... 0111011 @r
> +{
> + ssub 1101001 ..... ..... 000 ..... 0111011 @r
> + pssub_w 1101001 ..... ..... 000 ..... 0111011 @r
> +}
> +pssubu_b 1111010 ..... ..... 000 ..... 0111011 @r
> +pssubu_h 1111000 ..... ..... 000 ..... 0111011 @r
> +{
> + ssubu 1111001 ..... ..... 000 ..... 0111011 @r
> + pssubu_w 1111001 ..... ..... 000 ..... 0111011 @r
> +}
> +psati_h 11100 001.... ..... 100 ..... 0011011 @p_ui16
> +pusati_h 10100 001.... ..... 100 ..... 0011011 @p_ui16
> +{
> + sati_32 11100 01..... ..... 100 ..... 0011011 @p_ui32
> + psati_w 11100 01..... ..... 100 ..... 0011011 @p_ui32
> +}
> +{
> + usati_32 10100 01..... ..... 100 ..... 0011011 @p_ui32
> + pusati_w 10100 01..... ..... 100 ..... 0011011 @p_ui32
> +}
> +sati_64 111001 ...... ..... 100 ..... 0011011 @p_ui64
> +usati_64 101001 ...... ..... 100 ..... 0011011 @p_ui64
> diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> new file mode 100644
> index 00000000000..056ccfb486e
> --- /dev/null
> +++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> @@ -0,0 +1,547 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/* RISC-V translation routines for the P Standard Extensions. */
> +/* Copyright (c) 2026 ISRC ISCAS. */
> +
> +/* Save a 64 bit data in src to dst and dst + 1 */
> +
> +static bool require_rvp(DisasContext *ctx)
> +{
> + uint32_t opcode = ctx->opcode & 0x7f;
> +
> + if (!has_ext(ctx, RVP)) {
> + return false;
> + }
> +
> + /*
> + * P_VXSAT_EXCP is encoded in the TB flags only when P is implemented
> + * without Zve*, where stateen0.VXSAT controls the whole OP-32 and
> + * OP-IMM-32 P instruction spaces. When Zve* is present, this field
> + * remains NONE and vxsat access is checked by the VS path instead.
> + */
> + if ((opcode == 0x3b || opcode == 0x1b) &&
> + ctx->p_vxsat_excp != P_VXSAT_EXCP_NONE) {
> + ctx->virt_inst_excp =
> + ctx->p_vxsat_excp == P_VXSAT_EXCP_VIRTUAL;
> + return false;
> + }
> +
> + return true;
> +}
> +
> +static bool prepare_rvp_vxsat(DisasContext *ctx)
> +{
> + if (!ctx->cfg_ptr->ext_zve32x) {
> + return true;
> + }
> +
> + if (ctx->mstatus_vs == EXT_STATUS_DISABLED) {
> + return false;
> + }
> +
> + mark_vs_dirty(ctx);
> + return true;
> +}
> +
> +#define REQUIRE_RVP(ctx) do { \
> + if (!require_rvp(ctx)) { \
> + return false; \
> + } \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_BODY(NAME, VXSAT) \
> +do { \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
> + TCGv dest = dest_gpr(ctx, a->rd); \
> + gen_helper_##NAME(dest, tcg_env, src1, src2); \
> + gen_set_gpr(ctx, a->rd, dest); \
> + return true; \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_UNAVAILABLE_32(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_UNAVAILABLE_64(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_BODY(NAME, false); \
> +}
> +
> +#define GEN_SIMD_TRANS_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_BODY(NAME, true); \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_32(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + GEN_SIMD_TRANS_BODY(NAME, false); \
> +}
> +#define GEN_SIMD_TRANS_32_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + GEN_SIMD_TRANS_BODY(NAME, true); \
> +}
> +#else
> +#define GEN_SIMD_TRANS_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_64(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_BODY(NAME, false); \
> +}
> +#define GEN_SIMD_TRANS_64_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_BODY(NAME, true); \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_ACC_BODY(NAME, VXSAT) \
> +do { \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
> + TCGv dest = dest_gpr(ctx, a->rd); \
> + TCGv t = tcg_temp_new(); \
> + gen_helper_##NAME(t, tcg_env, src1, src2, dest); \
> + gen_set_gpr(ctx, a->rd, t); \
> + return true; \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_ACC(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_ACC_BODY(NAME, false); \
> +}
> +
> +#define GEN_SIMD_TRANS_ACC_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_ACC_BODY(NAME, true); \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_ACC_32(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + GEN_SIMD_TRANS_ACC_BODY(NAME, false); \
> +}
> +#else
> +#define GEN_SIMD_TRANS_ACC_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_ACC_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_ACC_64(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_ACC_BODY(NAME, false); \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_R1_BODY(NAME, VXSAT) \
> +do { \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv dest = dest_gpr(ctx, a->rd); \
> + gen_helper_##NAME(dest, tcg_env, src1); \
> + gen_set_gpr(ctx, a->rd, dest); \
> + return true; \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_R1(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_R1_BODY(NAME, false); \
> +}
> +
> +#define GEN_SIMD_TRANS_R1_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_R1_BODY(NAME, true); \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_R1_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_R1_64(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_R1_BODY(NAME, false); \
> +}
> +#define GEN_SIMD_TRANS_R1_64_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_R1_BODY(NAME, true); \
> +}
> +#endif
> +
> +#define GEN_SIMD_TRANS_IMM_BODY(NAME, VXSAT) \
> +do { \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv imm = tcg_constant_tl(a->imm); \
> + TCGv dest = dest_gpr(ctx, a->rd); \
> + gen_helper_##NAME(dest, tcg_env, src1, imm); \
> + gen_set_gpr(ctx, a->rd, dest); \
> + return true; \
> +} while (0)
> +
> +#define GEN_SIMD_TRANS_IMM(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, false); \
> +}
> +
> +#define GEN_SIMD_TRANS_IMM_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, true); \
> +}
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_IMM_32(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, false); \
> +}
> +#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, true); \
> +}
> +#else
> +#define GEN_SIMD_TRANS_IMM_32(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_IMM_32_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_IMM_64(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_64(NAME)
> +#else
> +#define GEN_SIMD_TRANS_IMM_64(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, false); \
> +}
> +#define GEN_SIMD_TRANS_IMM_64_VXSAT(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_64BIT(ctx); \
> + GEN_SIMD_TRANS_IMM_BODY(NAME, true); \
> +}
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, SRC2) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + TCGv_i32 src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv_i32 src2 = SRC2; \
> + TCGv_i64 t = tcg_temp_new_i64(); \
> + gen_helper_##NAME(t, tcg_env, src1, src2); \
> + set_pair_regs(ctx, (a->rd) * 2, t); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) \
> + GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE))
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) \
> + GEN_SIMD_TRANS_REG_PAIR_SCALAR_OP(NAME, tcg_constant_i32(a->imm))
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, SRC2_0, SRC2_1, VXSAT) \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
> + TCGv src2_0 = SRC2_0; \
> + TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2); \
> + TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
> + TCGv src2_1 = SRC2_1; \
> + TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1); \
> + gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2_0); \
> + gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2_1); \
> + gen_set_gpr(ctx, (a->rd) * 2, dest_0); \
> + gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
> + get_gpr(ctx, (a->rs2) * 2, EXT_NONE), \
> + get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
> + get_gpr(ctx, (a->rs2) * 2, EXT_NONE), \
> + get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE), true)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
> + tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_OP(INSN, HELPER, \
> + tcg_constant_tl(a->imm), tcg_constant_tl(a->imm), true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, VXSAT) \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
> + TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2); \
> + TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
> + TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1); \
> + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
> + gen_helper_##HELPER(dest_0, tcg_env, src1_0, src2); \
> + gen_helper_##HELPER(dest_1, tcg_env, src1_1, src2); \
> + gen_set_gpr(ctx, (a->rd) * 2, dest_0); \
> + gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_OP(INSN, HELPER, true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, VXSAT) \
> +static bool trans_##INSN(DisasContext *ctx, arg_##INSN * a) \
> +{ \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
> + TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2); \
> + TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
> + TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1); \
> + gen_helper_##HELPER(dest_0, tcg_env, src1_0); \
> + gen_helper_##HELPER(dest_1, tcg_env, src1_1); \
> + gen_set_gpr(ctx, (a->rd) * 2, dest_0); \
> + gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, false)
> +
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_OP(INSN, HELPER, true)
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#define GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(INSN, HELPER) \
> + GEN_SIMD_TRANS_UNAVAILABLE_32(INSN)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
> + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
> + TCGv_i64 t = tcg_temp_new_i64(); \
> + if (a->rd == 0) { \
> + tcg_gen_movi_i64(t, 0); \
> + } else { \
> + get_pair_regs(ctx, t, (a->rd) * 2); \
> + } \
> + gen_helper_##NAME(t, tcg_env, src1, src2, t); \
> + set_pair_regs(ctx, (a->rd) * 2, t); \
> + return true; \
> +}
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_ACC(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + TCGv_i32 src1_l; \
> + TCGv_i32 src1_h; \
> + TCGv_i32 src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
> + TCGv_i32 dest = dest_gpr(ctx, a->rd); \
> + if (a->rs1 == 0) { \
> + src1_l = tcg_temp_new_i32(); \
> + src1_h = tcg_temp_new_i32(); \
> + tcg_gen_movi_i32(src1_l, 0); \
> + tcg_gen_movi_i32(src1_h, 0); \
> + } else { \
> + src1_l = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
> + src1_h = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
> + } \
> + gen_helper_##NAME(dest, tcg_env, src1_l, src1_h, src2); \
> + gen_set_gpr(ctx, a->rd, dest); \
> + return true; \
> +}
> +#else
> +#define GEN_SIMD_TRANS_REG_PAIR_PREDSUM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +#if defined(TARGET_RISCV32)
> +#define GEN_SIMD_TRANS_PN_OP(NAME, SRC2, VXSAT) \
> +static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
> +{ \
> + REQUIRE_32BIT(ctx); \
> + REQUIRE_RVP(ctx); \
> + if (VXSAT && !prepare_rvp_vxsat(ctx)) { \
> + return false; \
> + } \
> + TCGv_i64 s1 = tcg_temp_new_i64(); \
> + if (a->rs1 == 0) { \
> + tcg_gen_mov_i64(s1, 0); \
> + } else { \
> + get_pair_regs(ctx, s1, a->rs1 * 2); \
> + } \
> + TCGv src2 = SRC2; \
> + TCGv dest = dest_gpr(ctx, a->rd); \
> + gen_helper_##NAME(dest, tcg_env, s1, src2); \
> + gen_set_gpr(ctx, a->rd, dest); \
> + return true; \
> +}
> +
> +#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) \
> + GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), false)
> +
> +#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) \
> + GEN_SIMD_TRANS_PN_OP(NAME, tcg_constant_tl(a->imm), true)
> +
> +#define GEN_SIMD_TRANS_PN_OP_REG(NAME) \
> + GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), false)
> +
> +#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) \
> + GEN_SIMD_TRANS_PN_OP(NAME, get_gpr(ctx, a->rs2, EXT_NONE), true)
> +#else
> +#define GEN_SIMD_TRANS_PN_OP_IMM(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_REG(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#define GEN_SIMD_TRANS_PN_OP_REG_VXSAT(NAME) GEN_SIMD_TRANS_UNAVAILABLE_32(NAME)
> +#endif
> +
> +/* Packed SIMD - Arithmetic Operations(Non-Saturating and Saturating) */
> +GEN_SIMD_TRANS(padd_b)
> +GEN_SIMD_TRANS(padd_h)
> +GEN_SIMD_TRANS_64(padd_w)
> +GEN_SIMD_TRANS(padd_bs)
> +GEN_SIMD_TRANS(padd_hs)
> +GEN_SIMD_TRANS_64(padd_ws)
> +GEN_SIMD_TRANS(psub_b)
> +GEN_SIMD_TRANS(psub_h)
> +GEN_SIMD_TRANS_64(psub_w)
> +GEN_SIMD_TRANS(psh1add_h)
> +GEN_SIMD_TRANS_64(psh1add_w)
> +GEN_SIMD_TRANS_VXSAT(pssh1sadd_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssh1sadd_w)
> +GEN_SIMD_TRANS_32_VXSAT(ssh1sadd)
> +GEN_SIMD_TRANS_VXSAT(psadd_b)
> +GEN_SIMD_TRANS_VXSAT(psadd_h)
> +GEN_SIMD_TRANS_64_VXSAT(psadd_w)
> +GEN_SIMD_TRANS_VXSAT(psaddu_b)
> +GEN_SIMD_TRANS_VXSAT(psaddu_h)
> +GEN_SIMD_TRANS_64_VXSAT(psaddu_w)
> +GEN_SIMD_TRANS_32_VXSAT(sadd)
> +GEN_SIMD_TRANS_32_VXSAT(saddu)
> +GEN_SIMD_TRANS_VXSAT(pssub_b)
> +GEN_SIMD_TRANS_VXSAT(pssub_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssub_w)
> +GEN_SIMD_TRANS_VXSAT(pssubu_b)
> +GEN_SIMD_TRANS_VXSAT(pssubu_h)
> +GEN_SIMD_TRANS_64_VXSAT(pssubu_w)
> +GEN_SIMD_TRANS_32_VXSAT(ssub)
> +GEN_SIMD_TRANS_32_VXSAT(ssubu)
> +GEN_SIMD_TRANS_IMM_VXSAT(psati_h)
> +GEN_SIMD_TRANS_IMM_VXSAT(pusati_h)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(psati_w)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(pusati_w)
> +GEN_SIMD_TRANS_IMM_32_VXSAT(sati_32)
> +GEN_SIMD_TRANS_IMM_32_VXSAT(usati_32)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(sati_64)
> +GEN_SIMD_TRANS_IMM_64_VXSAT(usati_64)
> +
> diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
> index 2948bbb2a86..52c58e0287e 100644
> --- a/target/riscv/tcg/psimd_helper.c
> +++ b/target/riscv/tcg/psimd_helper.c
> @@ -1654,3 +1654,117 @@ uint32_t HELPER(NAME)(CPURISCVState *env, uint64_t s1, uint32_t shamt) \
>
> /* Basic addition operations (non-saturating) */
>
> +GEN_PSIMD_BINOP(padd_b, target_ulong, uint8_t, uint8_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP(padd_h, target_ulong, uint16_t, uint16_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP(padd_w, uint64_t, uint32_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +GEN_PSIMD_BINOP_SCALAR(padd_bs, target_ulong, uint8_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP_SCALAR(padd_hs, target_ulong, uint16_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_BINOP_SCALAR(padd_ws, uint64_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +/* Basic subtraction operations (non-saturating) */
> +
> +GEN_PSIMD_BINOP(psub_b, target_ulong, uint8_t, uint8_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
> +GEN_PSIMD_BINOP(psub_h, target_ulong, uint16_t, uint16_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
> +GEN_PSIMD_BINOP(psub_w, uint64_t, uint32_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
> +
> +/* Shift-left-by-one and add operations */
> +
> +GEN_PSIMD_SHADD(psh1add_h, target_ulong, uint16_t,
> + EXTRACT16, INSERT16, ELEMS_H, 1)
> +GEN_PSIMD_SHADD(psh1add_w, uint64_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W, 1)
> +
> +GEN_PSIMD_SAT_SHADD(pssh1sadd_h, target_ulong, int16_t, int32_t,
> + EXTRACT16, INSERT16, ELEMS_H, 1, -0x4000, 0x3fff,
> + SAT_MIN_H, SAT_MAX_H, signed_saturate_h)
> +GEN_PSIMD_SAT_SHADD(pssh1sadd_w, uint64_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
> + 0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
> +
> +GEN_PSIMD_SAT_SHADD(ssh1sadd, uint32_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, 1, -0x40000000,
> + 0x3fffffff, SAT_MIN_W, SAT_MAX_W, signed_saturate_w)
> +
> +/* Saturating addition operations */
> +
> +GEN_PSIMD_SAT_BINOP(psadd_b, target_ulong, int8_t, int32_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
> + signed_saturate_b)
> +GEN_PSIMD_SAT_BINOP(psadd_h, target_ulong, int16_t, int32_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
> + signed_saturate_h)
> +GEN_PSIMD_SAT_BINOP(psadd_w, uint64_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> + signed_saturate_w)
> +
> +GEN_PSIMD_SAT_BINOP(psaddu_b, target_ulong, uint8_t, uint32_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD,
> + unsigned_saturate_b)
> +GEN_PSIMD_SAT_BINOP(psaddu_h, target_ulong, uint16_t, uint32_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD,
> + unsigned_saturate_h)
> +GEN_PSIMD_SAT_BINOP(psaddu_w, uint64_t, uint32_t, uint64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> + unsigned_saturate_w)
> +
> +GEN_PSIMD_SAT_BINOP(sadd, uint32_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> + signed_saturate_w)
> +GEN_PSIMD_SAT_BINOP(saddu, uint32_t, uint32_t, uint64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD,
> + unsigned_saturate_w)
> +
> +/* Saturating subtraction operations */
> +
> +GEN_PSIMD_SAT_BINOP(pssub_b, target_ulong, int8_t, int32_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB,
> + signed_saturate_b)
> +GEN_PSIMD_SAT_BINOP(pssub_h, target_ulong, int16_t, int32_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB,
> + signed_saturate_h)
> +GEN_PSIMD_SAT_BINOP(pssub_w, uint64_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
> + signed_saturate_w)
> +
> +GEN_PSIMD_USUB_SAT(pssubu_b, target_ulong, uint8_t,
> + EXTRACT8, INSERT8, ELEMS_B)
> +GEN_PSIMD_USUB_SAT(pssubu_h, target_ulong, uint16_t,
> + EXTRACT16, INSERT16, ELEMS_H)
> +GEN_PSIMD_USUB_SAT(pssubu_w, uint64_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W)
> +
> +GEN_PSIMD_SAT_BINOP(ssub, uint32_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB,
> + signed_saturate_w)
> +GEN_PSIMD_USUB_SAT(ssubu, uint32_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W)
> +
> +/* Saturation instructions (SAT, USAT) */
> +
> +GEN_PSIMD_SATI(psati_h, target_ulong, int16_t, int64_t,
> + EXTRACT16, INSERT16, ELEMS_H, 0x0f)
> +GEN_PSIMD_USATI(pusati_h, target_ulong, int16_t, uint16_t, uint32_t,
> + EXTRACT16, INSERT16, ELEMS_H, 1U)
> +GEN_PSIMD_SATI(psati_w, uint64_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, 0x1f)
> +GEN_PSIMD_USATI(pusati_w, uint64_t, int32_t, uint32_t, uint64_t,
> + EXTRACT32, INSERT32, ELEMS_W, 1ULL)
> +GEN_PSIMD_SATI(sati_32, uint32_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, 0x1f)
> +GEN_PSIMD_USATI(usati_32, uint32_t, int32_t, uint32_t, uint32_t,
> + EXTRACT32, INSERT32, ELEMS_W, 1U)
> +GEN_PSIMD_SATI(sati_64, uint64_t, int64_t, int64_t,
> + EXTRACT64, INSERT64, ELEMS_D, 0x3f)
> +GEN_PSIMD_USATI(usati_64, uint64_t, int64_t, uint64_t, uint64_t,
> + EXTRACT64, INSERT64, ELEMS_D, 1ULL)
> +
> diff --git a/target/riscv/tcg/translate.c b/target/riscv/tcg/translate.c
> index 9684dbe7528..0df9d4190f1 100644
> --- a/target/riscv/tcg/translate.c
> +++ b/target/riscv/tcg/translate.c
> @@ -103,6 +103,7 @@ typedef struct DisasContext {
> bool vstart_eq_zero;
> bool vl_eq_vlmax;
> bool altfmt;
> + uint8_t p_vxsat_excp;
> CPUState *cs;
> TCGv zero;
> /* actual address width */
> @@ -1199,6 +1200,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
> #include "insn_trans/trans_rvh.c.inc"
> #include "insn_trans/trans_rvv.c.inc"
> #include "insn_trans/trans_rvb.c.inc"
> +#include "insn_trans/trans_rvp.c.inc"
> #include "insn_trans/trans_rvzicond.c.inc"
> #include "insn_trans/trans_rvzacas.c.inc"
> #include "insn_trans/trans_rvzabha.c.inc"
> @@ -1333,6 +1335,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
> ctx->vstart_eq_zero = FIELD_EX32(tb_flags, TB_FLAGS, VSTART_EQ_ZERO);
> ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
> ctx->altfmt = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS, ALTFMT);
> + ctx->p_vxsat_excp = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS,
> + P_VXSAT_EXCP);
> ctx->misa_mxl_max = mcc->def->misa_mxl_max;
> ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL);
> ctx->address_xl = FIELD_EX32(tb_flags, TB_FLAGS, AXL);
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 04/18] target/riscv: Add packed SIMD averaging and rounding instructions
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (2 preceding siblings ...)
2026-07-17 10:06 ` [PATCH v2 03/18] target/riscv: Add packed SIMD arithmetic instructions Molly Chen
@ 2026-07-17 10:06 ` Molly Chen
2026-07-27 18:58 ` Daniel Henrique Barboza
2026-07-17 10:06 ` [PATCH v2 05/18] target/riscv: Add packed SIMD absolute, difference, compare and mask instructions Molly Chen
` (15 subsequent siblings)
19 siblings, 1 reply; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:06 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/helper.h | 18 ++++++++++
target/riscv/insn32.decode | 26 ++++++++++++++
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 18 ++++++++++
target/riscv/tcg/psimd_helper.c | 40 +++++++++++++++++++++
4 files changed, 102 insertions(+)
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index eebb2febd95..7256f776ae6 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1399,3 +1399,21 @@ DEF_HELPER_3(sati_32, i32, env, i32, i32)
DEF_HELPER_3(usati_32, i32, env, i32, i32)
DEF_HELPER_3(sati_64, i64, env, i64, i64)
DEF_HELPER_3(usati_64, i64, env, i64, i64)
+
+/* Packed SIMD - Averaging and Rounding Operations */
+DEF_HELPER_3(paadd_b, tl, env, tl, tl)
+DEF_HELPER_3(paadd_h, tl, env, tl, tl)
+DEF_HELPER_3(paadd_w, i64, env, i64, i64)
+DEF_HELPER_3(paaddu_b, tl, env, tl, tl)
+DEF_HELPER_3(paaddu_h, tl, env, tl, tl)
+DEF_HELPER_3(paaddu_w, i64, env, i64, i64)
+DEF_HELPER_3(aadd, i32, env, i32, i32)
+DEF_HELPER_3(aaddu, i32, env, i32, i32)
+DEF_HELPER_3(pasub_b, tl, env, tl, tl)
+DEF_HELPER_3(pasub_h, tl, env, tl, tl)
+DEF_HELPER_3(pasub_w, i64, env, i64, i64)
+DEF_HELPER_3(pasubu_b, tl, env, tl, tl)
+DEF_HELPER_3(pasubu_h, tl, env, tl, tl)
+DEF_HELPER_3(pasubu_w, i64, env, i64, i64)
+DEF_HELPER_3(asub, i32, env, i32, i32)
+DEF_HELPER_3(asubu, i32, env, i32, i32)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 8da13669d73..005cc055b8a 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1147,3 +1147,29 @@ pusati_h 10100 001.... ..... 100 ..... 0011011 @p_ui16
}
sati_64 111001 ...... ..... 100 ..... 0011011 @p_ui64
usati_64 101001 ...... ..... 100 ..... 0011011 @p_ui64
+
+# Packed SIMD - Averaging and Rounding Operations
+paadd_b 1001110 ..... ..... 000 ..... 0111011 @r
+paadd_h 1001100 ..... ..... 000 ..... 0111011 @r
+{
+ aadd 1001101 ..... ..... 000 ..... 0111011 @r
+ paadd_w 1001101 ..... ..... 000 ..... 0111011 @r
+}
+paaddu_b 1011110 ..... ..... 000 ..... 0111011 @r
+paaddu_h 1011100 ..... ..... 000 ..... 0111011 @r
+{
+ aaddu 1011101 ..... ..... 000 ..... 0111011 @r
+ paaddu_w 1011101 ..... ..... 000 ..... 0111011 @r
+}
+pasub_b 1101110 ..... ..... 000 ..... 0111011 @r
+pasub_h 1101100 ..... ..... 000 ..... 0111011 @r
+{
+ asub 1101101 ..... ..... 000 ..... 0111011 @r
+ pasub_w 1101101 ..... ..... 000 ..... 0111011 @r
+}
+pasubu_b 1111110 ..... ..... 000 ..... 0111011 @r
+pasubu_h 1111100 ..... ..... 000 ..... 0111011 @r
+{
+ asubu 1111101 ..... ..... 000 ..... 0111011 @r
+ pasubu_w 1111101 ..... ..... 000 ..... 0111011 @r
+}
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 056ccfb486e..43c59aef182 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -545,3 +545,21 @@ GEN_SIMD_TRANS_IMM_32_VXSAT(usati_32)
GEN_SIMD_TRANS_IMM_64_VXSAT(sati_64)
GEN_SIMD_TRANS_IMM_64_VXSAT(usati_64)
+/* Packed SIMD - Averaging and Rounding Operations */
+GEN_SIMD_TRANS(paadd_b)
+GEN_SIMD_TRANS(paadd_h)
+GEN_SIMD_TRANS_64(paadd_w)
+GEN_SIMD_TRANS(paaddu_b)
+GEN_SIMD_TRANS(paaddu_h)
+GEN_SIMD_TRANS_64(paaddu_w)
+GEN_SIMD_TRANS_32(aadd)
+GEN_SIMD_TRANS_32(aaddu)
+GEN_SIMD_TRANS(pasub_b)
+GEN_SIMD_TRANS(pasub_h)
+GEN_SIMD_TRANS_64(pasub_w)
+GEN_SIMD_TRANS(pasubu_b)
+GEN_SIMD_TRANS(pasubu_h)
+GEN_SIMD_TRANS_64(pasubu_w)
+GEN_SIMD_TRANS_32(asub)
+GEN_SIMD_TRANS_32(asubu)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 52c58e0287e..162041a8f18 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -1768,3 +1768,43 @@ GEN_PSIMD_SATI(sati_64, uint64_t, int64_t, int64_t,
GEN_PSIMD_USATI(usati_64, uint64_t, int64_t, uint64_t, uint64_t,
EXTRACT64, INSERT64, ELEMS_D, 1ULL)
+/* Averaging Operations (non-saturating) */
+
+GEN_PSIMD_AVG_BINOP(paadd_b, target_ulong, int8_t, int16_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
+GEN_PSIMD_AVG_BINOP(paadd_h, target_ulong, int16_t, int32_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
+GEN_PSIMD_AVG_BINOP(paadd_w, uint64_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
+
+GEN_PSIMD_AVG_BINOP(paaddu_b, target_ulong, uint8_t, uint16_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
+GEN_PSIMD_AVG_BINOP(paaddu_h, target_ulong, uint16_t, uint32_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
+GEN_PSIMD_AVG_BINOP(paaddu_w, uint64_t, uint32_t, uint64_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
+
+GEN_PSIMD_AVG_BINOP(aadd, uint32_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
+GEN_PSIMD_AVG_BINOP(aaddu, uint32_t, uint32_t, uint64_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
+
+GEN_PSIMD_AVG_BINOP(pasub_b, target_ulong, int8_t, int16_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
+GEN_PSIMD_AVG_BINOP(pasub_h, target_ulong, int16_t, int32_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
+GEN_PSIMD_AVG_BINOP(pasub_w, uint64_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
+
+GEN_PSIMD_AVG_BINOP(pasubu_b, target_ulong, uint8_t, uint16_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
+GEN_PSIMD_AVG_BINOP(pasubu_h, target_ulong, uint16_t, uint32_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
+GEN_PSIMD_AVG_BINOP(pasubu_w, uint64_t, uint32_t, uint64_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
+
+GEN_PSIMD_AVG_BINOP(asub, uint32_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
+GEN_PSIMD_AVG_BINOP(asubu, uint32_t, uint32_t, uint64_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
+
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v2 04/18] target/riscv: Add packed SIMD averaging and rounding instructions
2026-07-17 10:06 ` [PATCH v2 04/18] target/riscv: Add packed SIMD averaging and rounding instructions Molly Chen
@ 2026-07-27 18:58 ` Daniel Henrique Barboza
0 siblings, 0 replies; 31+ messages in thread
From: Daniel Henrique Barboza @ 2026-07-27 18:58 UTC (permalink / raw)
To: Molly Chen, palmer, alistair.francis, liwei1518, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: qemu-riscv, qemu-devel
On 7/17/2026 7:06 AM, Molly Chen wrote:
> Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
> ---
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> target/riscv/helper.h | 18 ++++++++++
> target/riscv/insn32.decode | 26 ++++++++++++++
> target/riscv/tcg/insn_trans/trans_rvp.c.inc | 18 ++++++++++
> target/riscv/tcg/psimd_helper.c | 40 +++++++++++++++++++++
> 4 files changed, 102 insertions(+)
>
> diff --git a/target/riscv/helper.h b/target/riscv/helper.h
> index eebb2febd95..7256f776ae6 100644
> --- a/target/riscv/helper.h
> +++ b/target/riscv/helper.h
> @@ -1399,3 +1399,21 @@ DEF_HELPER_3(sati_32, i32, env, i32, i32)
> DEF_HELPER_3(usati_32, i32, env, i32, i32)
> DEF_HELPER_3(sati_64, i64, env, i64, i64)
> DEF_HELPER_3(usati_64, i64, env, i64, i64)
> +
> +/* Packed SIMD - Averaging and Rounding Operations */
> +DEF_HELPER_3(paadd_b, tl, env, tl, tl)
> +DEF_HELPER_3(paadd_h, tl, env, tl, tl)
> +DEF_HELPER_3(paadd_w, i64, env, i64, i64)
> +DEF_HELPER_3(paaddu_b, tl, env, tl, tl)
> +DEF_HELPER_3(paaddu_h, tl, env, tl, tl)
> +DEF_HELPER_3(paaddu_w, i64, env, i64, i64)
> +DEF_HELPER_3(aadd, i32, env, i32, i32)
> +DEF_HELPER_3(aaddu, i32, env, i32, i32)
> +DEF_HELPER_3(pasub_b, tl, env, tl, tl)
> +DEF_HELPER_3(pasub_h, tl, env, tl, tl)
> +DEF_HELPER_3(pasub_w, i64, env, i64, i64)
> +DEF_HELPER_3(pasubu_b, tl, env, tl, tl)
> +DEF_HELPER_3(pasubu_h, tl, env, tl, tl)
> +DEF_HELPER_3(pasubu_w, i64, env, i64, i64)
> +DEF_HELPER_3(asub, i32, env, i32, i32)
> +DEF_HELPER_3(asubu, i32, env, i32, i32)
> diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
> index 8da13669d73..005cc055b8a 100644
> --- a/target/riscv/insn32.decode
> +++ b/target/riscv/insn32.decode
> @@ -1147,3 +1147,29 @@ pusati_h 10100 001.... ..... 100 ..... 0011011 @p_ui16
> }
> sati_64 111001 ...... ..... 100 ..... 0011011 @p_ui64
> usati_64 101001 ...... ..... 100 ..... 0011011 @p_ui64
> +
> +# Packed SIMD - Averaging and Rounding Operations
> +paadd_b 1001110 ..... ..... 000 ..... 0111011 @r
> +paadd_h 1001100 ..... ..... 000 ..... 0111011 @r
> +{
> + aadd 1001101 ..... ..... 000 ..... 0111011 @r
> + paadd_w 1001101 ..... ..... 000 ..... 0111011 @r
> +}
> +paaddu_b 1011110 ..... ..... 000 ..... 0111011 @r
> +paaddu_h 1011100 ..... ..... 000 ..... 0111011 @r
> +{
> + aaddu 1011101 ..... ..... 000 ..... 0111011 @r
> + paaddu_w 1011101 ..... ..... 000 ..... 0111011 @r
> +}
> +pasub_b 1101110 ..... ..... 000 ..... 0111011 @r
> +pasub_h 1101100 ..... ..... 000 ..... 0111011 @r
> +{
> + asub 1101101 ..... ..... 000 ..... 0111011 @r
> + pasub_w 1101101 ..... ..... 000 ..... 0111011 @r
> +}
> +pasubu_b 1111110 ..... ..... 000 ..... 0111011 @r
> +pasubu_h 1111100 ..... ..... 000 ..... 0111011 @r
> +{
> + asubu 1111101 ..... ..... 000 ..... 0111011 @r
> + pasubu_w 1111101 ..... ..... 000 ..... 0111011 @r
> +}
> diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> index 056ccfb486e..43c59aef182 100644
> --- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> +++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
> @@ -545,3 +545,21 @@ GEN_SIMD_TRANS_IMM_32_VXSAT(usati_32)
> GEN_SIMD_TRANS_IMM_64_VXSAT(sati_64)
> GEN_SIMD_TRANS_IMM_64_VXSAT(usati_64)
>
> +/* Packed SIMD - Averaging and Rounding Operations */
> +GEN_SIMD_TRANS(paadd_b)
> +GEN_SIMD_TRANS(paadd_h)
> +GEN_SIMD_TRANS_64(paadd_w)
> +GEN_SIMD_TRANS(paaddu_b)
> +GEN_SIMD_TRANS(paaddu_h)
> +GEN_SIMD_TRANS_64(paaddu_w)
> +GEN_SIMD_TRANS_32(aadd)
> +GEN_SIMD_TRANS_32(aaddu)
> +GEN_SIMD_TRANS(pasub_b)
> +GEN_SIMD_TRANS(pasub_h)
> +GEN_SIMD_TRANS_64(pasub_w)
> +GEN_SIMD_TRANS(pasubu_b)
> +GEN_SIMD_TRANS(pasubu_h)
> +GEN_SIMD_TRANS_64(pasubu_w)
> +GEN_SIMD_TRANS_32(asub)
> +GEN_SIMD_TRANS_32(asubu)
> +
> diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
> index 52c58e0287e..162041a8f18 100644
> --- a/target/riscv/tcg/psimd_helper.c
> +++ b/target/riscv/tcg/psimd_helper.c
> @@ -1768,3 +1768,43 @@ GEN_PSIMD_SATI(sati_64, uint64_t, int64_t, int64_t,
> GEN_PSIMD_USATI(usati_64, uint64_t, int64_t, uint64_t, uint64_t,
> EXTRACT64, INSERT64, ELEMS_D, 1ULL)
>
> +/* Averaging Operations (non-saturating) */
> +
> +GEN_PSIMD_AVG_BINOP(paadd_b, target_ulong, int8_t, int16_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_AVG_BINOP(paadd_h, target_ulong, int16_t, int32_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_AVG_BINOP(paadd_w, uint64_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +GEN_PSIMD_AVG_BINOP(paaddu_b, target_ulong, uint8_t, uint16_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ADD)
> +GEN_PSIMD_AVG_BINOP(paaddu_h, target_ulong, uint16_t, uint32_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ADD)
> +GEN_PSIMD_AVG_BINOP(paaddu_w, uint64_t, uint32_t, uint64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +GEN_PSIMD_AVG_BINOP(aadd, uint32_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +GEN_PSIMD_AVG_BINOP(aaddu, uint32_t, uint32_t, uint64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_ADD)
> +
> +GEN_PSIMD_AVG_BINOP(pasub_b, target_ulong, int8_t, int16_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
> +GEN_PSIMD_AVG_BINOP(pasub_h, target_ulong, int16_t, int32_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
> +GEN_PSIMD_AVG_BINOP(pasub_w, uint64_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
> +
> +GEN_PSIMD_AVG_BINOP(pasubu_b, target_ulong, uint8_t, uint16_t,
> + EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_SUB)
> +GEN_PSIMD_AVG_BINOP(pasubu_h, target_ulong, uint16_t, uint32_t,
> + EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_SUB)
> +GEN_PSIMD_AVG_BINOP(pasubu_w, uint64_t, uint32_t, uint64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
> +
> +GEN_PSIMD_AVG_BINOP(asub, uint32_t, int32_t, int64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
> +GEN_PSIMD_AVG_BINOP(asubu, uint32_t, uint32_t, uint64_t,
> + EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
> +
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 05/18] target/riscv: Add packed SIMD absolute, difference, compare and mask instructions
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (3 preceding siblings ...)
2026-07-17 10:06 ` [PATCH v2 04/18] target/riscv: Add packed SIMD averaging and rounding instructions Molly Chen
@ 2026-07-17 10:06 ` Molly Chen
2026-07-17 10:06 ` [PATCH v2 06/18] target/riscv: Add packed SIMD shift instructions Molly Chen
` (14 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:06 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/helper.h | 38 +++++++++
target/riscv/insn32.decode | 44 ++++++++++
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 38 +++++++++
target/riscv/tcg/psimd_helper.c | 95 +++++++++++++++++++++
4 files changed, 215 insertions(+)
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 7256f776ae6..1628ca119ac 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1417,3 +1417,41 @@ DEF_HELPER_3(pasubu_h, tl, env, tl, tl)
DEF_HELPER_3(pasubu_w, i64, env, i64, i64)
DEF_HELPER_3(asub, i32, env, i32, i32)
DEF_HELPER_3(asubu, i32, env, i32, i32)
+
+/* Packed SIMD - Absolute Value and Difference Operations */
+DEF_HELPER_2(psabs_b, tl, env, tl)
+DEF_HELPER_2(psabs_h, tl, env, tl)
+DEF_HELPER_2(abs, tl, env, tl)
+DEF_HELPER_2(absw, i64, env, i64)
+DEF_HELPER_3(pabd_b, tl, env, tl, tl)
+DEF_HELPER_3(pabdu_b, tl, env, tl, tl)
+DEF_HELPER_3(pabd_h, tl, env, tl, tl)
+DEF_HELPER_3(pabdu_h, tl, env, tl, tl)
+DEF_HELPER_3(pabdsumu_b, tl, env, tl, tl)
+DEF_HELPER_4(pabdsumau_b, tl, env, tl, tl, tl)
+
+/* Packed SIMD - Comparison and Mask Generation Operations */
+DEF_HELPER_3(pmseq_b, tl, env, tl, tl)
+DEF_HELPER_3(pmslt_b, tl, env, tl, tl)
+DEF_HELPER_3(pmsltu_b, tl, env, tl, tl)
+DEF_HELPER_3(pmin_b, tl, env, tl, tl)
+DEF_HELPER_3(pminu_b, tl, env, tl, tl)
+DEF_HELPER_3(pmax_b, tl, env, tl, tl)
+DEF_HELPER_3(pmaxu_b, tl, env, tl, tl)
+DEF_HELPER_3(pmseq_h, tl, env, tl, tl)
+DEF_HELPER_3(pmslt_h, tl, env, tl, tl)
+DEF_HELPER_3(pmsltu_h, tl, env, tl, tl)
+DEF_HELPER_3(pmin_h, tl, env, tl, tl)
+DEF_HELPER_3(pminu_h, tl, env, tl, tl)
+DEF_HELPER_3(pmax_h, tl, env, tl, tl)
+DEF_HELPER_3(pmaxu_h, tl, env, tl, tl)
+DEF_HELPER_3(pmseq_w, i64, env, i64, i64)
+DEF_HELPER_3(pmslt_w, i64, env, i64, i64)
+DEF_HELPER_3(pmsltu_w, i64, env, i64, i64)
+DEF_HELPER_3(pmin_w, i64, env, i64, i64)
+DEF_HELPER_3(pminu_w, i64, env, i64, i64)
+DEF_HELPER_3(pmax_w, i64, env, i64, i64)
+DEF_HELPER_3(pmaxu_w, i64, env, i64, i64)
+DEF_HELPER_3(mseq, i32, env, i32, i32)
+DEF_HELPER_3(mslt, i32, env, i32, i32)
+DEF_HELPER_3(msltu, i32, env, i32, i32)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 005cc055b8a..0c60f2eac7a 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1173,3 +1173,47 @@ pasubu_h 1111100 ..... ..... 000 ..... 0111011 @r
asubu 1111101 ..... ..... 000 ..... 0111011 @r
pasubu_w 1111101 ..... ..... 000 ..... 0111011 @r
}
+
+# Packed SIMD - Absolute Value and Difference Operations
+psabs_b 1110010 00111 ..... 010 ..... 0011011 @r2
+psabs_h 1110000 00111 ..... 010 ..... 0011011 @r2
+abs 01100 0000111 ..... 001 ..... 0010011 @r2
+absw 01100 0000111 ..... 001 ..... 0011011 @r2
+pabd_b 1100110 ..... ..... 000 ..... 0111011 @r
+pabdu_b 1110110 ..... ..... 000 ..... 0111011 @r
+pabd_h 1100100 ..... ..... 000 ..... 0111011 @r
+pabdu_h 1110100 ..... ..... 000 ..... 0111011 @r
+pabdsumu_b 1011010 ..... ..... 001 ..... 0111011 @r
+pabdsumau_b 1011110 ..... ..... 001 ..... 0111011 @r
+
+# Packed SIMD - Comparison and Mask Generation Operations
+pmseq_b 1100010 ..... ..... 110 ..... 0111011 @r
+pmslt_b 1101010 ..... ..... 110 ..... 0111011 @r
+pmsltu_b 1101110 ..... ..... 110 ..... 0111011 @r
+pmin_b 1110010 ..... ..... 110 ..... 0111011 @r
+pminu_b 1110110 ..... ..... 110 ..... 0111011 @r
+pmax_b 1111010 ..... ..... 110 ..... 0111011 @r
+pmaxu_b 1111110 ..... ..... 110 ..... 0111011 @r
+pmseq_h 1100000 ..... ..... 110 ..... 0111011 @r
+pmslt_h 1101000 ..... ..... 110 ..... 0111011 @r
+pmsltu_h 1101100 ..... ..... 110 ..... 0111011 @r
+pmin_h 1110000 ..... ..... 110 ..... 0111011 @r
+pminu_h 1110100 ..... ..... 110 ..... 0111011 @r
+pmax_h 1111000 ..... ..... 110 ..... 0111011 @r
+pmaxu_h 1111100 ..... ..... 110 ..... 0111011 @r
+{
+ mseq 1100001 ..... ..... 110 ..... 0111011 @r
+ pmseq_w 1100001 ..... ..... 110 ..... 0111011 @r
+}
+{
+ mslt 1101001 ..... ..... 110 ..... 0111011 @r
+ pmslt_w 1101001 ..... ..... 110 ..... 0111011 @r
+}
+{
+ msltu 1101101 ..... ..... 110 ..... 0111011 @r
+ pmsltu_w 1101101 ..... ..... 110 ..... 0111011 @r
+}
+pmin_w 1110001 ..... ..... 110 ..... 0111011 @r
+pminu_w 1110101 ..... ..... 110 ..... 0111011 @r
+pmax_w 1111001 ..... ..... 110 ..... 0111011 @r
+pmaxu_w 1111101 ..... ..... 110 ..... 0111011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 43c59aef182..2ad8e818ba5 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -563,3 +563,41 @@ GEN_SIMD_TRANS_64(pasubu_w)
GEN_SIMD_TRANS_32(asub)
GEN_SIMD_TRANS_32(asubu)
+/* Packed SIMD - Absolute Value and Difference Operations */
+GEN_SIMD_TRANS_R1_VXSAT(psabs_b)
+GEN_SIMD_TRANS_R1_VXSAT(psabs_h)
+GEN_SIMD_TRANS_R1(abs)
+GEN_SIMD_TRANS_R1_64(absw)
+GEN_SIMD_TRANS(pabd_b)
+GEN_SIMD_TRANS(pabdu_b)
+GEN_SIMD_TRANS(pabd_h)
+GEN_SIMD_TRANS(pabdu_h)
+GEN_SIMD_TRANS(pabdsumu_b)
+GEN_SIMD_TRANS_ACC(pabdsumau_b)
+
+/* Packed SIMD - Comparison and Mask Generation Operations */
+GEN_SIMD_TRANS(pmseq_b)
+GEN_SIMD_TRANS(pmslt_b)
+GEN_SIMD_TRANS(pmsltu_b)
+GEN_SIMD_TRANS(pmin_b)
+GEN_SIMD_TRANS(pminu_b)
+GEN_SIMD_TRANS(pmax_b)
+GEN_SIMD_TRANS(pmaxu_b)
+GEN_SIMD_TRANS(pmseq_h)
+GEN_SIMD_TRANS(pmslt_h)
+GEN_SIMD_TRANS(pmsltu_h)
+GEN_SIMD_TRANS(pmin_h)
+GEN_SIMD_TRANS(pminu_h)
+GEN_SIMD_TRANS(pmax_h)
+GEN_SIMD_TRANS(pmaxu_h)
+GEN_SIMD_TRANS_64(pmseq_w)
+GEN_SIMD_TRANS_64(pmslt_w)
+GEN_SIMD_TRANS_64(pmsltu_w)
+GEN_SIMD_TRANS_64(pmin_w)
+GEN_SIMD_TRANS_64(pminu_w)
+GEN_SIMD_TRANS_64(pmax_w)
+GEN_SIMD_TRANS_64(pmaxu_w)
+GEN_SIMD_TRANS_32(mseq)
+GEN_SIMD_TRANS_32(mslt)
+GEN_SIMD_TRANS_32(msltu)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 162041a8f18..034afe5a054 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -1808,3 +1808,98 @@ GEN_PSIMD_AVG_BINOP(asub, uint32_t, int32_t, int64_t,
GEN_PSIMD_AVG_BINOP(asubu, uint32_t, uint32_t, uint64_t,
EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_SUB)
+/* Absolute value operations */
+
+GEN_PSIMD_ABS(psabs_b, target_ulong, int8_t,
+ EXTRACT8, INSERT8, ELEMS_B, INT8_MIN, INT8_MAX)
+GEN_PSIMD_ABS(psabs_h, target_ulong, int16_t,
+ EXTRACT16, INSERT16, ELEMS_H, INT16_MIN, INT16_MAX)
+
+GEN_PSIMD_SCALAR_ABS(abs, target_ulong, target_long, target_ulong)
+GEN_PSIMD_SCALAR_ABS(absw, uint64_t, int32_t, uint32_t)
+
+/* Absolute difference operations */
+
+GEN_PSIMD_BINOP(pabd_b, target_ulong, int8_t, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ABD)
+GEN_PSIMD_BINOP(pabdu_b, target_ulong, uint8_t, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_ABD)
+GEN_PSIMD_BINOP(pabd_h, target_ulong, int16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ABD)
+GEN_PSIMD_BINOP(pabdu_h, target_ulong, uint16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_ABD)
+
+/**
+ * PABDSUMU.B - Sum of unsigned absolute differences
+ * Returns sum(|rs1[i] - rs2[i]|) for all bytes
+ */
+target_ulong HELPER(pabdsumu_b)(CPURISCVState *env,
+ target_ulong rs1, target_ulong rs2)
+{
+ return psimd_abdsumu_b(rs1, rs2, 0);
+}
+
+/**
+ * PABDSUMAU.B - Accumulated sum of unsigned absolute differences
+ * rd = rd + sum(|rs1[i] - rs2[i]|)
+ */
+target_ulong HELPER(pabdsumau_b)(CPURISCVState *env, target_ulong rs1,
+ target_ulong rs2, target_ulong rd)
+{
+ return psimd_abdsumu_b(rs1, rs2, rd);
+}
+
+/* Comparison operations (producing masks) */
+
+GEN_PSIMD_BINOP(pmseq_b, target_ulong, uint8_t, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_EQ_MASK)
+GEN_PSIMD_BINOP(pmslt_b, target_ulong, int8_t, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_LT_MASK)
+GEN_PSIMD_BINOP(pmsltu_b, target_ulong, uint8_t, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_LT_MASK)
+GEN_PSIMD_BINOP(pmin_b, target_ulong, int8_t, int8_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_MIN)
+GEN_PSIMD_BINOP(pminu_b, target_ulong, uint8_t, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_MIN)
+GEN_PSIMD_BINOP(pmax_b, target_ulong, int8_t, int8_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_MAX)
+GEN_PSIMD_BINOP(pmaxu_b, target_ulong, uint8_t, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, PSIMD_DO_MAX)
+
+GEN_PSIMD_BINOP(pmseq_h, target_ulong, uint16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_EQ_MASK)
+GEN_PSIMD_BINOP(pmslt_h, target_ulong, int16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_LT_MASK)
+GEN_PSIMD_BINOP(pmsltu_h, target_ulong, uint16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_LT_MASK)
+GEN_PSIMD_BINOP(pmin_h, target_ulong, int16_t, int16_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_MIN)
+GEN_PSIMD_BINOP(pminu_h, target_ulong, uint16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_MIN)
+GEN_PSIMD_BINOP(pmax_h, target_ulong, int16_t, int16_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_MAX)
+GEN_PSIMD_BINOP(pmaxu_h, target_ulong, uint16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, PSIMD_DO_MAX)
+
+GEN_PSIMD_BINOP(pmseq_w, uint64_t, uint32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_EQ_MASK)
+GEN_PSIMD_BINOP(pmslt_w, uint64_t, int32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_LT_MASK)
+GEN_PSIMD_BINOP(pmsltu_w, uint64_t, uint32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_LT_MASK)
+GEN_PSIMD_BINOP(pmin_w, uint64_t, int32_t, int32_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_MIN)
+GEN_PSIMD_BINOP(pminu_w, uint64_t, uint32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_MIN)
+GEN_PSIMD_BINOP(pmax_w, uint64_t, int32_t, int32_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_MAX)
+GEN_PSIMD_BINOP(pmaxu_w, uint64_t, uint32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_MAX)
+
+GEN_PSIMD_BINOP(mseq, uint32_t, uint32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_EQ_MASK)
+GEN_PSIMD_BINOP(mslt, uint32_t, int32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_LT_MASK)
+GEN_PSIMD_BINOP(msltu, uint32_t, uint32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_LT_MASK)
+
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 06/18] target/riscv: Add packed SIMD shift instructions
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (4 preceding siblings ...)
2026-07-17 10:06 ` [PATCH v2 05/18] target/riscv: Add packed SIMD absolute, difference, compare and mask instructions Molly Chen
@ 2026-07-17 10:06 ` Molly Chen
2026-07-17 10:07 ` [PATCH v2 07/18] target/riscv: Add packed SIMD exchange instructions Molly Chen
` (13 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:06 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/helper.h | 43 ++++++
target/riscv/insn32.decode | 57 ++++++++
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 43 ++++++
target/riscv/tcg/psimd_helper.c | 149 ++++++++++++++++++++
4 files changed, 292 insertions(+)
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 1628ca119ac..d72323890f6 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1455,3 +1455,46 @@ DEF_HELPER_3(pmaxu_w, i64, env, i64, i64)
DEF_HELPER_3(mseq, i32, env, i32, i32)
DEF_HELPER_3(mslt, i32, env, i32, i32)
DEF_HELPER_3(msltu, i32, env, i32, i32)
+
+/* Packed SIMD - Shift Operations */
+DEF_HELPER_3(pslli_b, tl, env, tl, tl)
+DEF_HELPER_3(psll_bs, tl, env, tl, tl)
+DEF_HELPER_3(pslli_h, tl, env, tl, tl)
+DEF_HELPER_3(psll_hs, tl, env, tl, tl)
+DEF_HELPER_3(pslli_w, i64, env, i64, i64)
+DEF_HELPER_3(psll_ws, i64, env, i64, i64)
+DEF_HELPER_3(psrli_b, tl, env, tl, tl)
+DEF_HELPER_3(psrl_bs, tl, env, tl, tl)
+DEF_HELPER_3(psrli_h, tl, env, tl, tl)
+DEF_HELPER_3(psrl_hs, tl, env, tl, tl)
+DEF_HELPER_3(psrli_w, i64, env, i64, i64)
+DEF_HELPER_3(psrl_ws, i64, env, i64, i64)
+DEF_HELPER_3(psrai_b, tl, env, tl, tl)
+DEF_HELPER_3(psra_bs, tl, env, tl, tl)
+DEF_HELPER_3(psrai_h, tl, env, tl, tl)
+DEF_HELPER_3(psra_hs, tl, env, tl, tl)
+DEF_HELPER_3(psrai_w, i64, env, i64, i64)
+DEF_HELPER_3(psra_ws, i64, env, i64, i64)
+DEF_HELPER_3(psslai_h, tl, env, tl, tl)
+DEF_HELPER_3(psslai_w, i64, env, i64, i64)
+DEF_HELPER_3(sslai, i32, env, i32, i32)
+DEF_HELPER_3(psrari_h, tl, env, tl, tl)
+DEF_HELPER_3(psrari_w, i64, env, i64, i64)
+DEF_HELPER_3(srari_32, i32, env, i32, i32)
+DEF_HELPER_3(srari_64, i64, env, i64, i64)
+DEF_HELPER_3(pssha_hs, tl, env, tl, tl)
+DEF_HELPER_3(pssha_ws, i64, env, i64, i64)
+DEF_HELPER_3(psshar_hs, tl, env, tl, tl)
+DEF_HELPER_3(psshar_ws, i64, env, i64, i64)
+DEF_HELPER_3(ssha, i32, env, i32, i32)
+DEF_HELPER_3(sshar, i32, env, i32, i32)
+DEF_HELPER_3(sha, i64, env, i64, i64)
+DEF_HELPER_3(shar, i64, env, i64, i64)
+DEF_HELPER_3(psshl_hs, tl, env, tl, tl)
+DEF_HELPER_3(psshlr_hs, tl, env, tl, tl)
+DEF_HELPER_3(psshl_ws, i64, env, i64, i64)
+DEF_HELPER_3(psshlr_ws, i64, env, i64, i64)
+DEF_HELPER_3(sshl, i32, env, i32, i32)
+DEF_HELPER_3(sshlr, i32, env, i32, i32)
+DEF_HELPER_3(shl, i64, env, i64, i64)
+DEF_HELPER_3(shlr, i64, env, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 0c60f2eac7a..fb029bb512f 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -40,6 +40,7 @@
%imm_z6 26:1 15:5
%imm_mop5 30:1 26:2 20:2
%imm_mop3 30:1 26:2
+%imm_p_ui8 20:3
%imm_p_ui16 20:4
%imm_p_ui32 20:5
%imm_p_ui64 20:6
@@ -109,6 +110,7 @@
@mop5 . . .. .. .... .. ..... ... ..... ....... &mop5 imm=%imm_mop5 %rd %rs1
@mop3 . . .. .. . ..... ..... ... ..... ....... &mop3 imm=%imm_mop3 %rd %rs1 %rs2
+@p_ui8 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui8 %rs1 %rd
@p_ui16 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui16 %rs1 %rd
@p_ui32 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui32 %rs1 %rd
@p_ui64 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui64 %rs1 %rd
@@ -1217,3 +1219,58 @@ pmin_w 1110001 ..... ..... 110 ..... 0111011 @r
pminu_w 1110101 ..... ..... 110 ..... 0111011 @r
pmax_w 1111001 ..... ..... 110 ..... 0111011 @r
pmaxu_w 1111101 ..... ..... 110 ..... 0111011 @r
+
+# Packed SIMD - Shift Operations
+pslli_b 10000 0001... ..... 010 ..... 0011011 @p_ui8
+psll_bs 1000110 ..... ..... 010 ..... 0011011 @r
+pslli_h 10000 001.... ..... 010 ..... 0011011 @p_ui16
+psll_hs 1000100 ..... ..... 010 ..... 0011011 @r
+pslli_w 10000 01..... ..... 010 ..... 0011011 @p_ui32
+psll_ws 1000101 ..... ..... 010 ..... 0011011 @r
+psrli_b 10000 0001... ..... 100 ..... 0011011 @p_ui8
+psrl_bs 1000110 ..... ..... 100 ..... 0011011 @r
+psrli_h 10000 001.... ..... 100 ..... 0011011 @p_ui16
+psrl_hs 1000100 ..... ..... 100 ..... 0011011 @r
+psrli_w 10000 01..... ..... 100 ..... 0011011 @p_ui32
+psrl_ws 1000101 ..... ..... 100 ..... 0011011 @r
+psrai_b 11000 0001... ..... 100 ..... 0011011 @p_ui8
+psra_bs 1100110 ..... ..... 100 ..... 0011011 @r
+psrai_h 11000 001.... ..... 100 ..... 0011011 @p_ui16
+psra_hs 1100100 ..... ..... 100 ..... 0011011 @r
+psrai_w 11000 01..... ..... 100 ..... 0011011 @p_ui32
+psra_ws 1100101 ..... ..... 100 ..... 0011011 @r
+psslai_h 11010 001.... ..... 010 ..... 0011011 @p_ui16
+{
+ sslai 11010 01..... ..... 010 ..... 0011011 @p_ui32
+ psslai_w 11010 01..... ..... 010 ..... 0011011 @p_ui32
+}
+psrari_h 11010 001.... ..... 100 ..... 0011011 @p_ui16
+{
+ srari_32 11010 01..... ..... 100 ..... 0011011 @p_ui32
+ psrari_w 11010 01..... ..... 100 ..... 0011011 @p_ui32
+}
+srari_64 110101 ...... ..... 100 ..... 0011011 @p_ui64
+pssha_hs 1110100 ..... ..... 010 ..... 0011011 @r
+{
+ ssha 1110101 ..... ..... 010 ..... 0011011 @r
+ pssha_ws 1110101 ..... ..... 010 ..... 0011011 @r
+}
+psshar_hs 1111100 ..... ..... 010 ..... 0011011 @r
+{
+ sshar 1111101 ..... ..... 010 ..... 0011011 @r
+ psshar_ws 1111101 ..... ..... 010 ..... 0011011 @r
+}
+sha 1110111 ..... ..... 010 ..... 0011011 @r
+shar 1111111 ..... ..... 010 ..... 0011011 @r
+psshl_hs 1010100 ..... ..... 010 ..... 0011011 @r
+psshlr_hs 1011100 ..... ..... 010 ..... 0011011 @r
+{
+ psshl_ws 1010101 ..... ..... 010 ..... 0011011 @r
+ sshl 1010101 ..... ..... 010 ..... 0011011 @r
+}
+{
+ psshlr_ws 1011101 ..... ..... 010 ..... 0011011 @r
+ sshlr 1011101 ..... ..... 010 ..... 0011011 @r
+}
+shl 1010111 ..... ..... 010 ..... 0011011 @r
+shlr 1011111 ..... ..... 010 ..... 0011011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 2ad8e818ba5..fb82760a60c 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -601,3 +601,46 @@ GEN_SIMD_TRANS_32(mseq)
GEN_SIMD_TRANS_32(mslt)
GEN_SIMD_TRANS_32(msltu)
+/* Packed SIMD - Shift Operations */
+GEN_SIMD_TRANS_IMM(pslli_b)
+GEN_SIMD_TRANS(psll_bs)
+GEN_SIMD_TRANS_IMM(pslli_h)
+GEN_SIMD_TRANS(psll_hs)
+GEN_SIMD_TRANS_IMM_64(pslli_w)
+GEN_SIMD_TRANS_64(psll_ws)
+GEN_SIMD_TRANS_IMM(psrli_b)
+GEN_SIMD_TRANS(psrl_bs)
+GEN_SIMD_TRANS_IMM(psrli_h)
+GEN_SIMD_TRANS(psrl_hs)
+GEN_SIMD_TRANS_IMM_64(psrli_w)
+GEN_SIMD_TRANS_64(psrl_ws)
+GEN_SIMD_TRANS_IMM(psrai_b)
+GEN_SIMD_TRANS(psra_bs)
+GEN_SIMD_TRANS_IMM(psrai_h)
+GEN_SIMD_TRANS(psra_hs)
+GEN_SIMD_TRANS_IMM_64(psrai_w)
+GEN_SIMD_TRANS_64(psra_ws)
+GEN_SIMD_TRANS_IMM_VXSAT(psslai_h)
+GEN_SIMD_TRANS_IMM_64_VXSAT(psslai_w)
+GEN_SIMD_TRANS_IMM_32_VXSAT(sslai)
+GEN_SIMD_TRANS_IMM(psrari_h)
+GEN_SIMD_TRANS_IMM_64(psrari_w)
+GEN_SIMD_TRANS_IMM_32(srari_32)
+GEN_SIMD_TRANS_IMM_64(srari_64)
+GEN_SIMD_TRANS_VXSAT(pssha_hs)
+GEN_SIMD_TRANS_64_VXSAT(pssha_ws)
+GEN_SIMD_TRANS_VXSAT(psshar_hs)
+GEN_SIMD_TRANS_64_VXSAT(psshar_ws)
+GEN_SIMD_TRANS_32_VXSAT(ssha)
+GEN_SIMD_TRANS_32_VXSAT(sshar)
+GEN_SIMD_TRANS_64(sha)
+GEN_SIMD_TRANS_64(shar)
+GEN_SIMD_TRANS_VXSAT(psshl_hs)
+GEN_SIMD_TRANS_VXSAT(psshlr_hs)
+GEN_SIMD_TRANS_64_VXSAT(psshl_ws)
+GEN_SIMD_TRANS_64_VXSAT(psshlr_ws)
+GEN_SIMD_TRANS_32_VXSAT(sshl)
+GEN_SIMD_TRANS_32_VXSAT(sshlr)
+GEN_SIMD_TRANS_64(shl)
+GEN_SIMD_TRANS_64(shlr)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 034afe5a054..8b106a336f5 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -1903,3 +1903,152 @@ GEN_PSIMD_BINOP(mslt, uint32_t, int32_t, uint32_t,
GEN_PSIMD_BINOP(msltu, uint32_t, uint32_t, uint32_t,
EXTRACT32, INSERT32, ELEMS_W, PSIMD_DO_LT_MASK)
+/* Shift operations (immediate and register) */
+
+GEN_PSIMD_SHIFTOP(pslli_b, target_ulong, uint8_t, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, 0x07, PSIMD_DO_SLL)
+GEN_PSIMD_SHIFTOP(psll_bs, target_ulong, uint8_t, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, 0x07, PSIMD_DO_SLL)
+GEN_PSIMD_SHIFTOP(pslli_h, target_ulong, uint16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, 0x0f, PSIMD_DO_SLL)
+GEN_PSIMD_SHIFTOP(psll_hs, target_ulong, uint16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, 0x0f, PSIMD_DO_SLL)
+GEN_PSIMD_SHIFTOP(pslli_w, uint64_t, uint32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x1f, PSIMD_DO_SLL)
+GEN_PSIMD_SHIFTOP(psll_ws, uint64_t, uint32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x1f, PSIMD_DO_SLL)
+
+GEN_PSIMD_SHIFTOP(psrli_b, target_ulong, uint8_t, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, 0x07, PSIMD_DO_SRL)
+GEN_PSIMD_SHIFTOP(psrl_bs, target_ulong, uint8_t, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, 0x07, PSIMD_DO_SRL)
+GEN_PSIMD_SHIFTOP(psrli_h, target_ulong, uint16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, 0x0f, PSIMD_DO_SRL)
+GEN_PSIMD_SHIFTOP(psrl_hs, target_ulong, uint16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, 0x0f, PSIMD_DO_SRL)
+GEN_PSIMD_SHIFTOP(psrli_w, uint64_t, uint32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x1f, PSIMD_DO_SRL)
+GEN_PSIMD_SHIFTOP(psrl_ws, uint64_t, uint32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x1f, PSIMD_DO_SRL)
+
+GEN_PSIMD_SHIFTOP(psrai_b, target_ulong, int8_t, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, 0x07, PSIMD_DO_SRA)
+GEN_PSIMD_SHIFTOP(psra_bs, target_ulong, int8_t, uint8_t,
+ EXTRACT8, INSERT8, ELEMS_B, 0x07, PSIMD_DO_SRA)
+GEN_PSIMD_SHIFTOP(psrai_h, target_ulong, int16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, 0x0f, PSIMD_DO_SRA)
+GEN_PSIMD_SHIFTOP(psra_hs, target_ulong, int16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, 0x0f, PSIMD_DO_SRA)
+GEN_PSIMD_SHIFTOP(psrai_w, uint64_t, int32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x1f, PSIMD_DO_SRA)
+GEN_PSIMD_SHIFTOP(psra_ws, uint64_t, int32_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x1f, PSIMD_DO_SRA)
+
+/* Saturating shift operations */
+
+GEN_PSIMD_SAT_SHIFTOP(psslai_h, target_ulong, int16_t, int32_t,
+ EXTRACT16, INSERT16, ELEMS_H, 0x0f,
+ signed_saturate_h)
+GEN_PSIMD_SAT_SHIFTOP(psslai_w, uint64_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x1f,
+ signed_saturate_w)
+
+GEN_PSIMD_SAT_SHIFTOP(sslai, uint32_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x1f,
+ signed_saturate_w)
+
+/* Rounding shift operations */
+
+GEN_PSIMD_ROUND_SRAI(psrari_h, target_ulong, int16_t, int32_t,
+ EXTRACT16, INSERT16, ELEMS_H, 0x0f)
+GEN_PSIMD_ROUND_SRAI(psrari_w, uint64_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x1f)
+
+GEN_PSIMD_ROUND_SRAI(srari_32, uint32_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x1f)
+
+/**
+ * SRARI_64 - 64-bit scalar arithmetic shift right with rounding
+ */
+uint64_t HELPER(srari_64)(CPURISCVState *env, uint64_t rs1, uint64_t imm)
+{
+ int64_t a = (int64_t)rs1;
+ uint8_t shamt = imm & 0x3F;
+
+ if (shamt == 0) {
+ return rs1;
+ }
+
+ return (uint64_t)(((a >> (shamt - 1)) + 1) >> 1);
+}
+
+/* Variable shift operations (with saturation and rounding) */
+
+GEN_PSIMD_VAR_SSHA(pssha_hs, target_ulong, int16_t, int32_t,
+ EXTRACT16, INSERT16, ELEMS_H, 16, signed_saturate_h)
+GEN_PSIMD_VAR_SSHA(pssha_ws, uint64_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 32, signed_saturate_w)
+
+GEN_PSIMD_VAR_SSHAR(psshar_hs, target_ulong, int16_t, int32_t,
+ EXTRACT16, INSERT16, ELEMS_H, 16, SAT_MIN_H, SAT_MAX_H,
+ signed_saturate_h)
+GEN_PSIMD_VAR_SSHAR(psshar_ws, uint64_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 32, SAT_MIN_W, SAT_MAX_W,
+ signed_saturate_w)
+
+GEN_PSIMD_VAR_SSHA(ssha, uint32_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 32, signed_saturate_w)
+
+/**
+ * SSHAR - 32-bit scalar variable shift with rounding and saturation
+ */
+uint32_t HELPER(sshar)(CPURISCVState *env, uint32_t rs1, uint32_t rs2)
+{
+ int32_t a = (int32_t)rs1;
+ int8_t shamt = (int8_t)(rs2 & 0xFF);
+ int sat = 0;
+ int32_t res;
+
+ if (shamt >= 0) {
+ int64_t shifted = (int64_t)a << shamt;
+ res = signed_saturate_w(shifted, &sat);
+ } else {
+ int right = -shamt;
+ if (right >= 32) {
+ res = (a < 0) ? -1 : 0;
+ } else {
+ int64_t rounded = ((a >> (right - 1)) + 1) >> 1;
+ res = (int32_t)rounded;
+ }
+ }
+
+ if (sat) {
+ env->vxsat = 1;
+ }
+ return (uint32_t)res;
+}
+
+GEN_PSIMD_VAR_SRA64(sha, PSIMD_DO_SRA64)
+GEN_PSIMD_VAR_SRA64(shar, PSIMD_DO_RNDSRA64)
+
+GEN_PSIMD_VAR_USHL(psshl_hs, target_ulong, uint16_t, uint32_t,
+ EXTRACT16, INSERT16, ELEMS_H, 16, unsigned_saturate_h)
+
+GEN_PSIMD_VAR_USHLR(psshlr_hs, target_ulong, uint16_t, uint32_t,
+ EXTRACT16, INSERT16, ELEMS_H, 16, unsigned_saturate_h)
+
+GEN_PSIMD_VAR_USHL(psshl_ws, uint64_t, uint32_t, uint64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 32, unsigned_saturate_w)
+
+GEN_PSIMD_VAR_USHLR(psshlr_ws, uint64_t, uint32_t, uint64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 32, unsigned_saturate_w)
+
+GEN_PSIMD_VAR_USHL(sshl, uint32_t, uint32_t, uint64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 32, unsigned_saturate_w)
+
+GEN_PSIMD_VAR_USHLR(sshlr, uint32_t, uint32_t, uint64_t,
+ EXTRACT32, INSERT32, ELEMS_W, 32, unsigned_saturate_w)
+
+GEN_PSIMD_VAR_SRL64(shl, PSIMD_DO_SRL64)
+GEN_PSIMD_VAR_SRL64(shlr, PSIMD_DO_RNDSRL64)
+
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 07/18] target/riscv: Add packed SIMD exchange instructions
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (5 preceding siblings ...)
2026-07-17 10:06 ` [PATCH v2 06/18] target/riscv: Add packed SIMD shift instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
2026-07-17 10:07 ` [PATCH v2 08/18] target/riscv: Add packed SIMD horizontal reduction instructions Molly Chen
` (12 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/helper.h | 14 +++++++
target/riscv/insn32.decode | 14 +++++++
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 14 +++++++
target/riscv/tcg/psimd_helper.c | 44 +++++++++++++++++++++
4 files changed, 86 insertions(+)
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index d72323890f6..d0b13cf3c6a 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1498,3 +1498,17 @@ DEF_HELPER_3(sshl, i32, env, i32, i32)
DEF_HELPER_3(sshlr, i32, env, i32, i32)
DEF_HELPER_3(shl, i64, env, i64, i64)
DEF_HELPER_3(shlr, i64, env, i64, i64)
+
+/* Packed SIMD - Exchange Operations */
+DEF_HELPER_3(pas_hx, tl, env, tl, tl)
+DEF_HELPER_3(psa_hx, tl, env, tl, tl)
+DEF_HELPER_3(psas_hx, tl, env, tl, tl)
+DEF_HELPER_3(pssa_hx, tl, env, tl, tl)
+DEF_HELPER_3(paas_hx, tl, env, tl, tl)
+DEF_HELPER_3(pasa_hx, tl, env, tl, tl)
+DEF_HELPER_3(pas_wx, i64, env, i64, i64)
+DEF_HELPER_3(psa_wx, i64, env, i64, i64)
+DEF_HELPER_3(psas_wx, i64, env, i64, i64)
+DEF_HELPER_3(pssa_wx, i64, env, i64, i64)
+DEF_HELPER_3(paas_wx, i64, env, i64, i64)
+DEF_HELPER_3(pasa_wx, i64, env, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index fb029bb512f..e331ba6a38c 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1274,3 +1274,17 @@ psshlr_hs 1011100 ..... ..... 010 ..... 0011011 @r
}
shl 1010111 ..... ..... 010 ..... 0011011 @r
shlr 1011111 ..... ..... 010 ..... 0011011 @r
+
+# Packed SIMD - Exchange Operations
+pas_hx 1000000 ..... ..... 110 ..... 0111011 @r
+psa_hx 1000010 ..... ..... 110 ..... 0111011 @r
+psas_hx 1001000 ..... ..... 110 ..... 0111011 @r
+pssa_hx 1001010 ..... ..... 110 ..... 0111011 @r
+paas_hx 1001100 ..... ..... 110 ..... 0111011 @r
+pasa_hx 1001110 ..... ..... 110 ..... 0111011 @r
+pas_wx 1000001 ..... ..... 110 ..... 0111011 @r
+psa_wx 1000011 ..... ..... 110 ..... 0111011 @r
+psas_wx 1001001 ..... ..... 110 ..... 0111011 @r
+pssa_wx 1001011 ..... ..... 110 ..... 0111011 @r
+paas_wx 1001101 ..... ..... 110 ..... 0111011 @r
+pasa_wx 1001111 ..... ..... 110 ..... 0111011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index fb82760a60c..61e1fb8d816 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -644,3 +644,17 @@ GEN_SIMD_TRANS_32_VXSAT(sshlr)
GEN_SIMD_TRANS_64(shl)
GEN_SIMD_TRANS_64(shlr)
+/* Packed SIMD - Exchange Operations */
+GEN_SIMD_TRANS(pas_hx)
+GEN_SIMD_TRANS(psa_hx)
+GEN_SIMD_TRANS_VXSAT(psas_hx)
+GEN_SIMD_TRANS_VXSAT(pssa_hx)
+GEN_SIMD_TRANS(paas_hx)
+GEN_SIMD_TRANS(pasa_hx)
+GEN_SIMD_TRANS_64(pas_wx)
+GEN_SIMD_TRANS_64(psa_wx)
+GEN_SIMD_TRANS_64_VXSAT(psas_wx)
+GEN_SIMD_TRANS_64_VXSAT(pssa_wx)
+GEN_SIMD_TRANS_64(paas_wx)
+GEN_SIMD_TRANS_64(pasa_wx)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 8b106a336f5..ccc43b2dda0 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2052,3 +2052,47 @@ GEN_PSIMD_VAR_USHLR(sshlr, uint32_t, uint32_t, uint64_t,
GEN_PSIMD_VAR_SRL64(shl, PSIMD_DO_SRL64)
GEN_PSIMD_VAR_SRL64(shlr, PSIMD_DO_RNDSRL64)
+/* Exchange operations (AS/SA/AS/SA with X suffix) */
+
+GEN_PSIMD_XPAIR_BINOP(pas_hx, target_ulong, int16_t,
+ EXTRACT16, INSERT16, ELEMS_H,
+ PSIMD_DO_SUB, PSIMD_DO_ADD)
+GEN_PSIMD_XPAIR_BINOP(psa_hx, target_ulong, int16_t,
+ EXTRACT16, INSERT16, ELEMS_H,
+ PSIMD_DO_ADD, PSIMD_DO_SUB)
+
+GEN_PSIMD_XPAIR_SAT_BINOP(psas_hx, target_ulong, int16_t, int32_t,
+ EXTRACT16, INSERT16, ELEMS_H,
+ PSIMD_DO_SUB, PSIMD_DO_ADD, signed_saturate_h)
+GEN_PSIMD_XPAIR_SAT_BINOP(pssa_hx, target_ulong, int16_t, int32_t,
+ EXTRACT16, INSERT16, ELEMS_H,
+ PSIMD_DO_ADD, PSIMD_DO_SUB, signed_saturate_h)
+
+GEN_PSIMD_XPAIR_AVG_BINOP(paas_hx, target_ulong, int16_t, int32_t,
+ EXTRACT16, INSERT16, ELEMS_H,
+ PSIMD_DO_SUB, PSIMD_DO_ADD)
+GEN_PSIMD_XPAIR_AVG_BINOP(pasa_hx, target_ulong, int16_t, int32_t,
+ EXTRACT16, INSERT16, ELEMS_H,
+ PSIMD_DO_ADD, PSIMD_DO_SUB)
+
+GEN_PSIMD_XPAIR_BINOP(pas_wx, uint64_t, int32_t,
+ EXTRACT32, INSERT32, ELEMS_W,
+ PSIMD_DO_SUB, PSIMD_DO_ADD)
+GEN_PSIMD_XPAIR_BINOP(psa_wx, uint64_t, int32_t,
+ EXTRACT32, INSERT32, ELEMS_W,
+ PSIMD_DO_ADD, PSIMD_DO_SUB)
+
+GEN_PSIMD_XPAIR_SAT_BINOP(psas_wx, uint64_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W,
+ PSIMD_DO_SUB, PSIMD_DO_ADD, signed_saturate_w)
+GEN_PSIMD_XPAIR_SAT_BINOP(pssa_wx, uint64_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W,
+ PSIMD_DO_ADD, PSIMD_DO_SUB, signed_saturate_w)
+
+GEN_PSIMD_XPAIR_AVG_BINOP(paas_wx, uint64_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W,
+ PSIMD_DO_SUB, PSIMD_DO_ADD)
+GEN_PSIMD_XPAIR_AVG_BINOP(pasa_wx, uint64_t, int32_t, int64_t,
+ EXTRACT32, INSERT32, ELEMS_W,
+ PSIMD_DO_ADD, PSIMD_DO_SUB)
+
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 08/18] target/riscv: Add packed SIMD horizontal reduction instructions
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (6 preceding siblings ...)
2026-07-17 10:07 ` [PATCH v2 07/18] target/riscv: Add packed SIMD exchange instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
2026-07-17 10:07 ` [PATCH v2 09/18] target/riscv: Add packed SIMD pack, merge and count-leading instructions Molly Chen
` (11 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/helper.h | 8 ++++++++
target/riscv/insn32.decode | 8 ++++++++
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 8 ++++++++
target/riscv/tcg/psimd_helper.c | 15 +++++++++++++++
4 files changed, 39 insertions(+)
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index d0b13cf3c6a..5fe650c5d71 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1512,3 +1512,11 @@ DEF_HELPER_3(psas_wx, i64, env, i64, i64)
DEF_HELPER_3(pssa_wx, i64, env, i64, i64)
DEF_HELPER_3(paas_wx, i64, env, i64, i64)
DEF_HELPER_3(pasa_wx, i64, env, i64, i64)
+
+/* Packed SIMD - Horizontal Reduction Operations */
+DEF_HELPER_3(predsum_bs, tl, env, tl, tl)
+DEF_HELPER_3(predsumu_bs, tl, env, tl, tl)
+DEF_HELPER_3(predsum_hs, tl, env, tl, tl)
+DEF_HELPER_3(predsumu_hs, tl, env, tl, tl)
+DEF_HELPER_3(predsum_ws, i64, env, i64, i64)
+DEF_HELPER_3(predsumu_ws, i64, env, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index e331ba6a38c..9d0f5c48b6d 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1288,3 +1288,11 @@ psas_wx 1001001 ..... ..... 110 ..... 0111011 @r
pssa_wx 1001011 ..... ..... 110 ..... 0111011 @r
paas_wx 1001101 ..... ..... 110 ..... 0111011 @r
pasa_wx 1001111 ..... ..... 110 ..... 0111011 @r
+
+# Packed SIMD - Horizontal Reduction Operations
+predsum_bs 1001110 ..... ..... 100 ..... 0011011 @r
+predsumu_bs 1011110 ..... ..... 100 ..... 0011011 @r
+predsum_hs 1001100 ..... ..... 100 ..... 0011011 @r
+predsumu_hs 1011100 ..... ..... 100 ..... 0011011 @r
+predsum_ws 1001101 ..... ..... 100 ..... 0011011 @r
+predsumu_ws 1011101 ..... ..... 100 ..... 0011011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 61e1fb8d816..9f2ae9da1d1 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -658,3 +658,11 @@ GEN_SIMD_TRANS_64_VXSAT(pssa_wx)
GEN_SIMD_TRANS_64(paas_wx)
GEN_SIMD_TRANS_64(pasa_wx)
+/* Packed SIMD - Horizontal Reduction Operations */
+GEN_SIMD_TRANS(predsum_bs)
+GEN_SIMD_TRANS(predsumu_bs)
+GEN_SIMD_TRANS(predsum_hs)
+GEN_SIMD_TRANS(predsumu_hs)
+GEN_SIMD_TRANS_64(predsum_ws)
+GEN_SIMD_TRANS_64(predsumu_ws)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index ccc43b2dda0..0acf0414bf9 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2096,3 +2096,18 @@ GEN_PSIMD_XPAIR_AVG_BINOP(pasa_wx, uint64_t, int32_t, int64_t,
EXTRACT32, INSERT32, ELEMS_W,
PSIMD_DO_ADD, PSIMD_DO_SUB)
+/* Horizontal sum operations */
+
+GEN_PSIMD_REDSUM(predsum_bs, target_ulong, int64_t, int8_t,
+ EXTRACT8, ELEMS_B, (int64_t)(int32_t)rs2)
+GEN_PSIMD_REDSUM(predsumu_bs, target_ulong, uint64_t, uint8_t,
+ EXTRACT8, ELEMS_B, rs2)
+GEN_PSIMD_REDSUM(predsum_hs, target_ulong, int64_t, int16_t,
+ EXTRACT16, ELEMS_H, (int64_t)(int32_t)rs2)
+GEN_PSIMD_REDSUM(predsumu_hs, target_ulong, uint64_t, uint16_t,
+ EXTRACT16, ELEMS_H, rs2)
+GEN_PSIMD_REDSUM(predsum_ws, uint64_t, int64_t, int32_t,
+ EXTRACT32, ELEMS_W, (int64_t)rs2)
+GEN_PSIMD_REDSUM(predsumu_ws, uint64_t, uint64_t, uint32_t,
+ EXTRACT32, ELEMS_W, rs2)
+
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 09/18] target/riscv: Add packed SIMD pack, merge and count-leading instructions
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (7 preceding siblings ...)
2026-07-17 10:07 ` [PATCH v2 08/18] target/riscv: Add packed SIMD horizontal reduction instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
2026-07-17 10:07 ` [PATCH v2 10/18] target/riscv: Add packed SIMD multiplication instructions Molly Chen
` (10 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/helper.h | 41 ++++++
target/riscv/insn32.decode | 41 ++++++
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 41 ++++++
target/riscv/tcg/psimd_helper.c | 148 ++++++++++++++++++++
4 files changed, 271 insertions(+)
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 5fe650c5d71..f83af437d40 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1520,3 +1520,44 @@ DEF_HELPER_3(predsum_hs, tl, env, tl, tl)
DEF_HELPER_3(predsumu_hs, tl, env, tl, tl)
DEF_HELPER_3(predsum_ws, i64, env, i64, i64)
DEF_HELPER_3(predsumu_ws, i64, env, i64, i64)
+
+/* Packed SIMD - Pack, Unpack, and Merge Operations */
+DEF_HELPER_3(ppaire_b, tl, env, tl, tl)
+DEF_HELPER_3(ppaireo_b, tl, env, tl, tl)
+DEF_HELPER_3(ppairoe_b, tl, env, tl, tl)
+DEF_HELPER_3(ppairo_b, tl, env, tl, tl)
+DEF_HELPER_3(ppaire_h, i64, env, i64, i64)
+DEF_HELPER_3(ppaireo_h, tl, env, tl, tl)
+DEF_HELPER_3(ppairoe_h, tl, env, tl, tl)
+DEF_HELPER_3(ppairo_h, tl, env, tl, tl)
+DEF_HELPER_3(ppaireo_w, i64, env, i64, i64)
+DEF_HELPER_3(ppairoe_w, i64, env, i64, i64)
+DEF_HELPER_3(ppairo_w, i64, env, i64, i64)
+DEF_HELPER_2(psext_h_b, tl, env, tl)
+DEF_HELPER_2(psext_w_b, i64, env, i64)
+DEF_HELPER_2(psext_w_h, i64, env, i64)
+DEF_HELPER_2(rev, tl, env, tl)
+DEF_HELPER_2(rev16, i64, env, i64)
+DEF_HELPER_3(zip8p, i64, env, i64, i64)
+DEF_HELPER_3(zip8hp, i64, env, i64, i64)
+DEF_HELPER_3(unzip8p, i64, env, i64, i64)
+DEF_HELPER_3(unzip8hp, i64, env, i64, i64)
+DEF_HELPER_3(zip16p, i64, env, i64, i64)
+DEF_HELPER_3(zip16hp, i64, env, i64, i64)
+DEF_HELPER_3(unzip16p, i64, env, i64, i64)
+DEF_HELPER_3(unzip16hp, i64, env, i64, i64)
+DEF_HELPER_4(slx, tl, env, tl, tl, tl)
+DEF_HELPER_4(srx, tl, env, tl, tl, tl)
+DEF_HELPER_4(mvm, tl, env, tl, tl, tl)
+DEF_HELPER_4(mvmn, tl, env, tl, tl, tl)
+DEF_HELPER_4(merge, tl, env, tl, tl, tl)
+DEF_HELPER_3(pnclipp_b, i64, env, i64, i64)
+DEF_HELPER_3(pnclipup_b, i64, env, i64, i64)
+DEF_HELPER_3(pnclipp_h, i64, env, i64, i64)
+DEF_HELPER_3(pnclipup_h, i64, env, i64, i64)
+DEF_HELPER_3(pnclipp_w, i64, env, i64, i64)
+DEF_HELPER_3(pnclipup_w, i64, env, i64, i64)
+
+/* Packed SIMD - Count Leading Operations */
+DEF_HELPER_2(cls, tl, env, tl)
+DEF_HELPER_2(clsw, i64, env, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 9d0f5c48b6d..14dab4cb641 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1296,3 +1296,44 @@ predsum_hs 1001100 ..... ..... 100 ..... 0011011 @r
predsumu_hs 1011100 ..... ..... 100 ..... 0011011 @r
predsum_ws 1001101 ..... ..... 100 ..... 0011011 @r
predsumu_ws 1011101 ..... ..... 100 ..... 0011011 @r
+
+# Packed SIMD - Pack, Unpack, and Merge Operations
+ppaire_b 1000000 ..... ..... 100 ..... 0111011 @r
+ppaireo_b 1001000 ..... ..... 100 ..... 0111011 @r
+ppairoe_b 1010000 ..... ..... 100 ..... 0111011 @r
+ppairo_b 1011000 ..... ..... 100 ..... 0111011 @r
+ppaireo_h 1001001 ..... ..... 100 ..... 0111011 @r
+ppairoe_h 1010001 ..... ..... 100 ..... 0111011 @r
+ppairo_h 1011001 ..... ..... 100 ..... 0111011 @r
+ppaire_h 1000001 ..... ..... 100 ..... 0111011 @r
+ppaireo_w 1001011 ..... ..... 100 ..... 0111011 @r
+ppairoe_w 1010011 ..... ..... 100 ..... 0111011 @r
+ppairo_w 1011011 ..... ..... 100 ..... 0111011 @r
+psext_h_b 1110000 00100 ..... 010 ..... 0011011 @r2
+psext_w_b 1110001 00100 ..... 010 ..... 0011011 @r2
+psext_w_h 1110001 00101 ..... 010 ..... 0011011 @r2
+rev 01101 0111111 ..... 101 ..... 0010011 @r2
+rev16 01101 0110000 ..... 101 ..... 0010011 @r2
+zip8p 1111000 ..... ..... 010 ..... 0111011 @r
+zip8hp 1111010 ..... ..... 010 ..... 0111011 @r
+unzip8p 1110000 ..... ..... 010 ..... 0111011 @r
+unzip8hp 1110010 ..... ..... 010 ..... 0111011 @r
+zip16p 1111001 ..... ..... 010 ..... 0111011 @r
+zip16hp 1111011 ..... ..... 010 ..... 0111011 @r
+unzip16p 1110001 ..... ..... 010 ..... 0111011 @r
+unzip16hp 1110011 ..... ..... 010 ..... 0111011 @r
+slx 1000111 ..... ..... 001 ..... 0111011 @r
+srx 1010111 ..... ..... 001 ..... 0111011 @r
+mvm 1010100 ..... ..... 001 ..... 0111011 @r
+mvmn 1010101 ..... ..... 001 ..... 0111011 @r
+merge 1010110 ..... ..... 001 ..... 0111011 @r
+pnclipp_b 1100000 ..... ..... 010 ..... 0111011 @r
+pnclipup_b 1000000 ..... ..... 010 ..... 0111011 @r
+pnclipp_h 1100001 ..... ..... 010 ..... 0111011 @r
+pnclipup_h 1000001 ..... ..... 010 ..... 0111011 @r
+pnclipp_w 1100011 ..... ..... 010 ..... 0111011 @r
+pnclipup_w 1000011 ..... ..... 010 ..... 0111011 @r
+
+# Packed SIMD - Count Leading Operations
+cls 01100 0000011 ..... 001 ..... 0010011 @r2
+clsw 01100 0000011 ..... 001 ..... 0011011 @r2
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 9f2ae9da1d1..486184eeaf3 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -666,3 +666,44 @@ GEN_SIMD_TRANS(predsumu_hs)
GEN_SIMD_TRANS_64(predsum_ws)
GEN_SIMD_TRANS_64(predsumu_ws)
+/* Packed SIMD - Pack, Unpack, and Merge Operations */
+GEN_SIMD_TRANS(ppaire_b)
+GEN_SIMD_TRANS(ppaireo_b)
+GEN_SIMD_TRANS(ppairoe_b)
+GEN_SIMD_TRANS(ppairo_b)
+GEN_SIMD_TRANS_64(ppaire_h)
+GEN_SIMD_TRANS(ppaireo_h)
+GEN_SIMD_TRANS(ppairoe_h)
+GEN_SIMD_TRANS(ppairo_h)
+GEN_SIMD_TRANS_64(ppaireo_w)
+GEN_SIMD_TRANS_64(ppairoe_w)
+GEN_SIMD_TRANS_64(ppairo_w)
+GEN_SIMD_TRANS_R1(psext_h_b)
+GEN_SIMD_TRANS_R1_64(psext_w_b)
+GEN_SIMD_TRANS_R1_64(psext_w_h)
+GEN_SIMD_TRANS_R1(rev)
+GEN_SIMD_TRANS_R1_64(rev16)
+GEN_SIMD_TRANS_64(zip8p)
+GEN_SIMD_TRANS_64(zip8hp)
+GEN_SIMD_TRANS_64(unzip8p)
+GEN_SIMD_TRANS_64(unzip8hp)
+GEN_SIMD_TRANS_64(zip16p)
+GEN_SIMD_TRANS_64(zip16hp)
+GEN_SIMD_TRANS_64(unzip16p)
+GEN_SIMD_TRANS_64(unzip16hp)
+GEN_SIMD_TRANS_ACC(slx)
+GEN_SIMD_TRANS_ACC(srx)
+GEN_SIMD_TRANS_ACC(mvm)
+GEN_SIMD_TRANS_ACC(mvmn)
+GEN_SIMD_TRANS_ACC(merge)
+GEN_SIMD_TRANS_64_VXSAT(pnclipp_b)
+GEN_SIMD_TRANS_64_VXSAT(pnclipup_b)
+GEN_SIMD_TRANS_64_VXSAT(pnclipp_h)
+GEN_SIMD_TRANS_64_VXSAT(pnclipup_h)
+GEN_SIMD_TRANS_64_VXSAT(pnclipp_w)
+GEN_SIMD_TRANS_64_VXSAT(pnclipup_w)
+
+/* Packed SIMD - Count Leading Operations */
+GEN_SIMD_TRANS_R1(cls)
+GEN_SIMD_TRANS_R1_64(clsw)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 0acf0414bf9..99f11f084f2 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2111,3 +2111,151 @@ GEN_PSIMD_REDSUM(predsum_ws, uint64_t, int64_t, int32_t,
GEN_PSIMD_REDSUM(predsumu_ws, uint64_t, uint64_t, uint32_t,
EXTRACT32, ELEMS_W, rs2)
+/* Packing/unpacking operations */
+
+GEN_PSIMD_PAIR_PACK(ppaire_b, target_ulong, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, 0x00ff, 8,
+ PSIMD_PAIR_LO, PSIMD_PAIR_LO)
+GEN_PSIMD_PAIR_PACK(ppaireo_b, target_ulong, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, 0x00ff, 8,
+ PSIMD_PAIR_HI, PSIMD_PAIR_LO)
+GEN_PSIMD_PAIR_PACK(ppairoe_b, target_ulong, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, 0x00ff, 8,
+ PSIMD_PAIR_LO, PSIMD_PAIR_HI)
+GEN_PSIMD_PAIR_PACK(ppairo_b, target_ulong, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, 0x00ff, 8,
+ PSIMD_PAIR_HI, PSIMD_PAIR_HI)
+
+GEN_PSIMD_PAIR_PACK(ppaire_h, uint64_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x0000ffff, 16,
+ PSIMD_PAIR_LO, PSIMD_PAIR_LO)
+GEN_PSIMD_PAIR_PACK(ppaireo_h, target_ulong, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x0000ffff, 16,
+ PSIMD_PAIR_HI, PSIMD_PAIR_LO)
+GEN_PSIMD_PAIR_PACK(ppairoe_h, target_ulong, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x0000ffff, 16,
+ PSIMD_PAIR_LO, PSIMD_PAIR_HI)
+GEN_PSIMD_PAIR_PACK(ppairo_h, target_ulong, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 0x0000ffff, 16,
+ PSIMD_PAIR_HI, PSIMD_PAIR_HI)
+
+GEN_PSIMD_PAIR_WORD(ppaireo_w, 0, 1)
+GEN_PSIMD_PAIR_WORD(ppairoe_w, 1, 0)
+GEN_PSIMD_PAIR_WORD(ppairo_w, 1, 1)
+
+GEN_PSIMD_SIGN_EXTEND(psext_h_b, target_ulong, int8_t, int16_t,
+ EXTRACT8, INSERT16, ELEMS_H, 2)
+GEN_PSIMD_SIGN_EXTEND(psext_w_b, uint64_t, int8_t, int32_t,
+ EXTRACT8, INSERT32, ELEMS_W, 4)
+GEN_PSIMD_SIGN_EXTEND(psext_w_h, uint64_t, int16_t, int32_t,
+ EXTRACT16, INSERT32, ELEMS_W, 2)
+
+/**
+ * REV - Reverse all bits
+ */
+target_ulong HELPER(rev)(CPURISCVState *env, target_ulong rs1)
+{
+ target_ulong rd = 0;
+
+ for (int i = 0; i < TARGET_LONG_BITS; i++) {
+ rd = (rd << 1) | (rs1 & 1);
+ rs1 >>= 1;
+ }
+
+ return rd;
+}
+
+/**
+ * REV16 - Reverse 16-bit chunks (RV64 only)
+ */
+uint64_t HELPER(rev16)(CPURISCVState *env, uint64_t rs1)
+{
+ uint64_t rd = 0;
+
+ for (int i = 0; i < 4; i++) {
+ uint16_t chunk = EXTRACT16(rs1, i);
+ rd = (rd << 16) | chunk;
+ }
+
+ return rd;
+}
+
+GEN_PSIMD_ZIP(zip8p, uint8_t, EXTRACT8, 4, 8, 3)
+GEN_PSIMD_ZIP(zip8hp, uint8_t, EXTRACT8, 4, 8, 7)
+GEN_PSIMD_UNZIP(unzip8p, EXTRACT8, 4, 8, 0)
+GEN_PSIMD_UNZIP(unzip8hp, EXTRACT8, 4, 8, 1)
+
+GEN_PSIMD_ZIP(zip16p, uint16_t, EXTRACT16, 2, 16, 1)
+GEN_PSIMD_ZIP(zip16hp, uint16_t, EXTRACT16, 2, 16, 3)
+GEN_PSIMD_UNZIP(unzip16p, EXTRACT16, 2, 16, 0)
+GEN_PSIMD_UNZIP(unzip16hp, EXTRACT16, 2, 16, 1)
+
+/* Merge and mask operations */
+
+/**
+ * SLX - Shift left extended (concatenate rd and rs1, shift left, take upper)
+ */
+target_ulong HELPER(slx)(CPURISCVState *env, target_ulong rs1,
+ target_ulong rs2, target_ulong rd)
+{
+ int shamt = (TARGET_LONG_BITS == 32) ? (rs2 & 0x1F) : (rs2 & 0x3F);
+ target_ulong xrs1 = 0;
+ target_ulong xrd = 0;
+
+ if (shamt <= TARGET_LONG_BITS) {
+ xrs1 = rs1 >> (TARGET_LONG_BITS - shamt);
+ xrd = (rd << shamt) + xrs1;
+ } else {
+ xrd = rs1 << (shamt - TARGET_LONG_BITS);
+ }
+
+ return xrd;
+}
+
+/**
+ * SRX - Shift right extended (concatenate rs1 and rd, shift right, take lower)
+ */
+target_ulong HELPER(srx)(CPURISCVState *env, target_ulong rs1,
+ target_ulong rs2, target_ulong rd)
+{
+ int shamt = (TARGET_LONG_BITS == 32) ? (rs2 & 0x1F) : (rs2 & 0x3F);
+ target_ulong xrs1 = 0;
+ target_ulong xrd = 0;
+
+ if (shamt <= TARGET_LONG_BITS) {
+ xrs1 = rs1 << (TARGET_LONG_BITS - shamt);
+ xrd = (rd >> shamt) + xrs1;
+ } else {
+ xrd = rs1 >> (shamt - TARGET_LONG_BITS);
+ }
+
+ return xrd;
+}
+
+GEN_PSIMD_BIT_SELECT(mvm, rs2, rs1, rd)
+GEN_PSIMD_BIT_SELECT(mvmn, rs2, rd, rs1)
+GEN_PSIMD_BIT_SELECT(merge, rd, rs2, rs1)
+
+GEN_PSIMD_NCLIP_PACK(pnclipp_b, int16_t, int8_t,
+ EXTRACT16, INSERT8, 4, signed_saturate_b)
+GEN_PSIMD_NCLIP_PACK(pnclipup_b, uint16_t, uint8_t,
+ EXTRACT16, INSERT8, 4, unsigned_saturate_b)
+GEN_PSIMD_NCLIP_PACK(pnclipp_h, int32_t, int16_t,
+ EXTRACT32, INSERT16, 2, signed_saturate_h)
+GEN_PSIMD_NCLIP_PACK(pnclipup_h, uint32_t, uint16_t,
+ EXTRACT32, INSERT16, 2, unsigned_saturate_h)
+GEN_PSIMD_NCLIP_PACK(pnclipp_w, int64_t, int32_t,
+ EXTRACT64, INSERT32_64, 1, signed_saturate_w)
+GEN_PSIMD_NCLIP_PACK(pnclipup_w, uint64_t, uint32_t,
+ EXTRACT64, INSERT32_64, 1, unsigned_saturate_w)
+
+/* Count leading operations */
+
+#if TARGET_LONG_BITS == 64
+GEN_PSIMD_CLS(cls, target_ulong, uint64_t, clrsb64)
+#else
+GEN_PSIMD_CLS(cls, target_ulong, uint32_t, clrsb32)
+#endif
+
+GEN_PSIMD_CLS(clsw, uint64_t, uint32_t, clrsb32)
+
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 10/18] target/riscv: Add packed SIMD multiplication instructions
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (8 preceding siblings ...)
2026-07-17 10:07 ` [PATCH v2 09/18] target/riscv: Add packed SIMD pack, merge and count-leading instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
2026-07-17 10:07 ` [PATCH v2 11/18] target/riscv: Add packed SIMD multiply-accumulate instructions Molly Chen
` (9 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/helper.h | 63 +++++++
target/riscv/insn32.decode | 93 ++++++++++
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 63 +++++++
target/riscv/tcg/psimd_helper.c | 184 ++++++++++++++++++++
4 files changed, 403 insertions(+)
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index f83af437d40..f06f40b1284 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1561,3 +1561,66 @@ DEF_HELPER_3(pnclipup_w, i64, env, i64, i64)
/* Packed SIMD - Count Leading Operations */
DEF_HELPER_2(cls, tl, env, tl)
DEF_HELPER_2(clsw, i64, env, i64)
+
+/* Packed SIMD - Pure Multiplication Operations */
+DEF_HELPER_3(pmulh_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulhsu_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulhu_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulhr_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulhrsu_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulhru_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulh_w, i64, env, i64, i64)
+DEF_HELPER_3(pmulhr_w, i64, env, i64, i64)
+DEF_HELPER_3(pmulhsu_w, i64, env, i64, i64)
+DEF_HELPER_3(pmulhrsu_w, i64, env, i64, i64)
+DEF_HELPER_3(pmulhu_w, i64, env, i64, i64)
+DEF_HELPER_3(pmulhru_w, i64, env, i64, i64)
+DEF_HELPER_3(mulhr, i32, env, i32, i32)
+DEF_HELPER_3(mulhrsu, i32, env, i32, i32)
+DEF_HELPER_3(mulhru, i32, env, i32, i32)
+DEF_HELPER_3(pmulh_h_b0, tl, env, tl, tl)
+DEF_HELPER_3(pmulh_h_b1, tl, env, tl, tl)
+DEF_HELPER_3(pmulhsu_h_b0, tl, env, tl, tl)
+DEF_HELPER_3(pmulhsu_h_b1, tl, env, tl, tl)
+DEF_HELPER_3(mulh_h0, i32, env, i32, i32)
+DEF_HELPER_3(mulh_h1, i32, env, i32, i32)
+DEF_HELPER_3(mulhsu_h0, i32, env, i32, i32)
+DEF_HELPER_3(mulhsu_h1, i32, env, i32, i32)
+DEF_HELPER_3(pmulh_w_h0, i64, env, i64, i64)
+DEF_HELPER_3(pmulh_w_h1, i64, env, i64, i64)
+DEF_HELPER_3(pmulhsu_w_h0, i64, env, i64, i64)
+DEF_HELPER_3(pmulhsu_w_h1, i64, env, i64, i64)
+DEF_HELPER_3(pmul_h_b00, tl, env, tl, tl)
+DEF_HELPER_3(pmul_h_b01, tl, env, tl, tl)
+DEF_HELPER_3(pmul_h_b11, tl, env, tl, tl)
+DEF_HELPER_3(pmulsu_h_b00, tl, env, tl, tl)
+DEF_HELPER_3(pmulsu_h_b11, tl, env, tl, tl)
+DEF_HELPER_3(pmulu_h_b00, tl, env, tl, tl)
+DEF_HELPER_3(pmulu_h_b01, tl, env, tl, tl)
+DEF_HELPER_3(pmulu_h_b11, tl, env, tl, tl)
+DEF_HELPER_3(pmul_w_h00, i64, env, i64, i64)
+DEF_HELPER_3(pmul_w_h01, i64, env, i64, i64)
+DEF_HELPER_3(pmul_w_h11, i64, env, i64, i64)
+DEF_HELPER_3(pmulsu_w_h00, i64, env, i64, i64)
+DEF_HELPER_3(pmulsu_w_h11, i64, env, i64, i64)
+DEF_HELPER_3(pmulu_w_h00, i64, env, i64, i64)
+DEF_HELPER_3(pmulu_w_h01, i64, env, i64, i64)
+DEF_HELPER_3(pmulu_w_h11, i64, env, i64, i64)
+DEF_HELPER_3(pm2sadd_h, tl, env, tl, tl)
+DEF_HELPER_3(pm2sadd_hx, tl, env, tl, tl)
+DEF_HELPER_3(mul_h00, i32, env, i32, i32)
+DEF_HELPER_3(mul_h01, i32, env, i32, i32)
+DEF_HELPER_3(mul_h11, i32, env, i32, i32)
+DEF_HELPER_3(mulsu_h00, i32, env, i32, i32)
+DEF_HELPER_3(mulsu_h11, i32, env, i32, i32)
+DEF_HELPER_3(mulu_h00, i32, env, i32, i32)
+DEF_HELPER_3(mulu_h01, i32, env, i32, i32)
+DEF_HELPER_3(mulu_h11, i32, env, i32, i32)
+DEF_HELPER_3(mul_w00, i64, env, i64, i64)
+DEF_HELPER_3(mul_w01, i64, env, i64, i64)
+DEF_HELPER_3(mul_w11, i64, env, i64, i64)
+DEF_HELPER_3(mulsu_w00, i64, env, i64, i64)
+DEF_HELPER_3(mulsu_w11, i64, env, i64, i64)
+DEF_HELPER_3(mulu_w00, i64, env, i64, i64)
+DEF_HELPER_3(mulu_w01, i64, env, i64, i64)
+DEF_HELPER_3(mulu_w11, i64, env, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 14dab4cb641..cc0cc35fe24 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1337,3 +1337,96 @@ pnclipup_w 1000011 ..... ..... 010 ..... 0111011 @r
# Packed SIMD - Count Leading Operations
cls 01100 0000011 ..... 001 ..... 0010011 @r2
clsw 01100 0000011 ..... 001 ..... 0011011 @r2
+
+# Packed SIMD - Pure Multiplication Operations
+pmulh_h 10000 00 ..... ..... 111 ..... 0111011 @r
+pmulhsu_h 11000 00 ..... ..... 111 ..... 0111011 @r
+pmulhu_h 10010 00 ..... ..... 111 ..... 0111011 @r
+pmulhr_h 10000 10 ..... ..... 111 ..... 0111011 @r
+pmulhrsu_h 11000 10 ..... ..... 111 ..... 0111011 @r
+pmulhru_h 10010 10 ..... ..... 111 ..... 0111011 @r
+pmulh_w 10000 01 ..... ..... 111 ..... 0111011 @r
+{
+ mulhr 10000 11 ..... ..... 111 ..... 0111011 @r
+ pmulhr_w 10000 11 ..... ..... 111 ..... 0111011 @r
+}
+pmulhsu_w 11000 01 ..... ..... 111 ..... 0111011 @r
+{
+ mulhrsu 11000 11 ..... ..... 111 ..... 0111011 @r
+ pmulhrsu_w 11000 11 ..... ..... 111 ..... 0111011 @r
+}
+pmulhu_w 10010 01 ..... ..... 111 ..... 0111011 @r
+{
+ mulhru 10010 11 ..... ..... 111 ..... 0111011 @r
+ pmulhru_w 10010 11 ..... ..... 111 ..... 0111011 @r
+}
+pmulh_h_b0 10100 00 ..... ..... 111 ..... 0111011 @r
+pmulh_h_b1 10110 00 ..... ..... 111 ..... 0111011 @r
+pmulhsu_h_b0 10100 10 ..... ..... 111 ..... 0111011 @r
+pmulhsu_h_b1 10110 10 ..... ..... 111 ..... 0111011 @r
+{
+ mulh_h0 10100 01 ..... ..... 111 ..... 0111011 @r
+ pmulh_w_h0 10100 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+ mulh_h1 10110 01 ..... ..... 111 ..... 0111011 @r
+ pmulh_w_h1 10110 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+ mulhsu_h0 10100 11 ..... ..... 111 ..... 0111011 @r
+ pmulhsu_w_h0 10100 11 ..... ..... 111 ..... 0111011 @r
+}
+{
+ mulhsu_h1 10110 11 ..... ..... 111 ..... 0111011 @r
+ pmulhsu_w_h1 10110 11 ..... ..... 111 ..... 0111011 @r
+}
+pmul_h_b00 10000 00 ..... ..... 011 ..... 0111011 @r
+pmul_h_b01 10010 00 ..... ..... 001 ..... 0111011 @r
+pmul_h_b11 10010 00 ..... ..... 011 ..... 0111011 @r
+pmulsu_h_b00 11100 00 ..... ..... 011 ..... 0111011 @r
+pmulsu_h_b11 11110 00 ..... ..... 011 ..... 0111011 @r
+pmulu_h_b00 10100 00 ..... ..... 011 ..... 0111011 @r
+pmulu_h_b01 10110 00 ..... ..... 001 ..... 0111011 @r
+pmulu_h_b11 10110 00 ..... ..... 011 ..... 0111011 @r
+{
+ mul_h00 10000 01 ..... ..... 011 ..... 0111011 @r
+ pmul_w_h00 10000 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+ mul_h01 10010 01 ..... ..... 001 ..... 0111011 @r
+ pmul_w_h01 10010 01 ..... ..... 001 ..... 0111011 @r
+}
+{
+ mul_h11 10010 01 ..... ..... 011 ..... 0111011 @r
+ pmul_w_h11 10010 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+ mulsu_h00 11100 01 ..... ..... 011 ..... 0111011 @r
+ pmulsu_w_h00 11100 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+ mulsu_h11 11110 01 ..... ..... 011 ..... 0111011 @r
+ pmulsu_w_h11 11110 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+ mulu_h00 10100 01 ..... ..... 011 ..... 0111011 @r
+ pmulu_w_h00 10100 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+ mulu_h01 10110 01 ..... ..... 001 ..... 0111011 @r
+ pmulu_w_h01 10110 01 ..... ..... 001 ..... 0111011 @r
+}
+{
+ mulu_h11 10110 01 ..... ..... 011 ..... 0111011 @r
+ pmulu_w_h11 10110 01 ..... ..... 011 ..... 0111011 @r
+}
+pm2sadd_h 11000 10 ..... ..... 101 ..... 0111011 @r
+pm2sadd_hx 11010 10 ..... ..... 101 ..... 0111011 @r
+mul_w00 10000 11 ..... ..... 011 ..... 0111011 @r
+mul_w01 10010 11 ..... ..... 001 ..... 0111011 @r
+mul_w11 10010 11 ..... ..... 011 ..... 0111011 @r
+mulsu_w00 11100 11 ..... ..... 011 ..... 0111011 @r
+mulsu_w11 11110 11 ..... ..... 011 ..... 0111011 @r
+mulu_w00 10100 11 ..... ..... 011 ..... 0111011 @r
+mulu_w01 10110 11 ..... ..... 001 ..... 0111011 @r
+mulu_w11 10110 11 ..... ..... 011 ..... 0111011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 486184eeaf3..7edea099d01 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -707,3 +707,66 @@ GEN_SIMD_TRANS_64_VXSAT(pnclipup_w)
GEN_SIMD_TRANS_R1(cls)
GEN_SIMD_TRANS_R1_64(clsw)
+/* Packed SIMD - Pure Multiplication Operations */
+GEN_SIMD_TRANS(pmulh_h)
+GEN_SIMD_TRANS(pmulhsu_h)
+GEN_SIMD_TRANS(pmulhu_h)
+GEN_SIMD_TRANS(pmulhr_h)
+GEN_SIMD_TRANS(pmulhrsu_h)
+GEN_SIMD_TRANS(pmulhru_h)
+GEN_SIMD_TRANS_64(pmulh_w)
+GEN_SIMD_TRANS_64(pmulhr_w)
+GEN_SIMD_TRANS_64(pmulhsu_w)
+GEN_SIMD_TRANS_64(pmulhrsu_w)
+GEN_SIMD_TRANS_64(pmulhu_w)
+GEN_SIMD_TRANS_64(pmulhru_w)
+GEN_SIMD_TRANS_32(mulhr)
+GEN_SIMD_TRANS_32(mulhrsu)
+GEN_SIMD_TRANS_32(mulhru)
+GEN_SIMD_TRANS(pmulh_h_b0)
+GEN_SIMD_TRANS(pmulh_h_b1)
+GEN_SIMD_TRANS(pmulhsu_h_b0)
+GEN_SIMD_TRANS(pmulhsu_h_b1)
+GEN_SIMD_TRANS_32(mulh_h0)
+GEN_SIMD_TRANS_32(mulh_h1)
+GEN_SIMD_TRANS_32(mulhsu_h0)
+GEN_SIMD_TRANS_32(mulhsu_h1)
+GEN_SIMD_TRANS_64(pmulh_w_h0)
+GEN_SIMD_TRANS_64(pmulh_w_h1)
+GEN_SIMD_TRANS_64(pmulhsu_w_h0)
+GEN_SIMD_TRANS_64(pmulhsu_w_h1)
+GEN_SIMD_TRANS(pmul_h_b00)
+GEN_SIMD_TRANS(pmul_h_b01)
+GEN_SIMD_TRANS(pmul_h_b11)
+GEN_SIMD_TRANS(pmulsu_h_b00)
+GEN_SIMD_TRANS(pmulsu_h_b11)
+GEN_SIMD_TRANS(pmulu_h_b00)
+GEN_SIMD_TRANS(pmulu_h_b01)
+GEN_SIMD_TRANS(pmulu_h_b11)
+GEN_SIMD_TRANS_64(pmul_w_h00)
+GEN_SIMD_TRANS_64(pmul_w_h01)
+GEN_SIMD_TRANS_64(pmul_w_h11)
+GEN_SIMD_TRANS_64(pmulsu_w_h00)
+GEN_SIMD_TRANS_64(pmulsu_w_h11)
+GEN_SIMD_TRANS_64(pmulu_w_h00)
+GEN_SIMD_TRANS_64(pmulu_w_h01)
+GEN_SIMD_TRANS_64(pmulu_w_h11)
+GEN_SIMD_TRANS_VXSAT(pm2sadd_h)
+GEN_SIMD_TRANS_VXSAT(pm2sadd_hx)
+GEN_SIMD_TRANS_32(mul_h00)
+GEN_SIMD_TRANS_32(mul_h01)
+GEN_SIMD_TRANS_32(mul_h11)
+GEN_SIMD_TRANS_32(mulsu_h00)
+GEN_SIMD_TRANS_32(mulsu_h11)
+GEN_SIMD_TRANS_32(mulu_h00)
+GEN_SIMD_TRANS_32(mulu_h01)
+GEN_SIMD_TRANS_32(mulu_h11)
+GEN_SIMD_TRANS_64(mul_w00)
+GEN_SIMD_TRANS_64(mul_w01)
+GEN_SIMD_TRANS_64(mul_w11)
+GEN_SIMD_TRANS_64(mulsu_w00)
+GEN_SIMD_TRANS_64(mulsu_w11)
+GEN_SIMD_TRANS_64(mulu_w00)
+GEN_SIMD_TRANS_64(mulu_w01)
+GEN_SIMD_TRANS_64(mulu_w11)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 99f11f084f2..5be8fe257f8 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2259,3 +2259,187 @@ GEN_PSIMD_CLS(cls, target_ulong, uint32_t, clrsb32)
GEN_PSIMD_CLS(clsw, uint64_t, uint32_t, clrsb32)
+/* Pure multiplication operations */
+
+GEN_PSIMD_MUL_HIGH(pmulh_h, target_ulong, int16_t, int16_t, int32_t,
+ uint16_t, EXTRACT16, INSERT16, ELEMS_H, 16, 0,
+ PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH(pmulhsu_h, target_ulong, int16_t, uint16_t, int32_t,
+ uint16_t, EXTRACT16, INSERT16, ELEMS_H, 16, 0,
+ PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_HIGH(pmulhu_h, target_ulong, uint16_t, uint16_t, uint32_t,
+ uint16_t, EXTRACT16, INSERT16, ELEMS_H, 16, 0,
+ PSIMD_MUL_U32)
+GEN_PSIMD_MUL_HIGH(pmulhr_h, target_ulong, int16_t, int16_t, int32_t,
+ uint16_t, EXTRACT16, INSERT16, ELEMS_H, 16, 1 << 15,
+ PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH(pmulhrsu_h, target_ulong, int16_t, uint16_t, int32_t,
+ uint16_t, EXTRACT16, INSERT16, ELEMS_H, 16, 1 << 15,
+ PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_HIGH(pmulhru_h, target_ulong, uint16_t, uint16_t, uint32_t,
+ uint16_t, EXTRACT16, INSERT16, ELEMS_H, 16, 1 << 15,
+ PSIMD_MUL_U32)
+
+GEN_PSIMD_MUL_HIGH(pmulh_w, uint64_t, int32_t, int32_t, int64_t,
+ uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 0,
+ PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH(pmulhr_w, uint64_t, int32_t, int32_t, int64_t,
+ uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 1LL << 31,
+ PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH(pmulhsu_w, uint64_t, int32_t, uint32_t, int64_t,
+ uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 0,
+ PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH(pmulhrsu_w, uint64_t, int32_t, uint32_t, int64_t,
+ uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 1LL << 31,
+ PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH(pmulhu_w, uint64_t, uint32_t, uint32_t, uint64_t,
+ uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 0,
+ PSIMD_MUL_U64)
+GEN_PSIMD_MUL_HIGH(pmulhru_w, uint64_t, uint32_t, uint32_t, uint64_t,
+ uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 1LL << 31,
+ PSIMD_MUL_U64)
+
+GEN_PSIMD_MUL_HIGH(mulhr, uint32_t, int32_t, int32_t, int64_t,
+ uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 1LL << 31,
+ PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH(mulhrsu, uint32_t, int32_t, uint32_t, int64_t,
+ uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 1LL << 31,
+ PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH(mulhru, uint32_t, uint32_t, uint32_t, uint64_t,
+ uint32_t, EXTRACT32, INSERT32, ELEMS_W, 32, 1LL << 31,
+ PSIMD_MUL_U64)
+
+GEN_PSIMD_MUL_HIGH_SEL(pmulh_h_b0, target_ulong, int16_t, int8_t,
+ int32_t, uint16_t, EXTRACT16, EXTRACT8, INSERT16,
+ ELEMS_H, 2, 0, 8, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH_SEL(pmulh_h_b1, target_ulong, int16_t, int8_t,
+ int32_t, uint16_t, EXTRACT16, EXTRACT8, INSERT16,
+ ELEMS_H, 2, 1, 8, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH_SEL(pmulhsu_h_b0, target_ulong, int16_t, uint8_t,
+ int32_t, uint16_t, EXTRACT16, EXTRACT8, INSERT16,
+ ELEMS_H, 2, 0, 8, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_HIGH_SEL(pmulhsu_h_b1, target_ulong, int16_t, uint8_t,
+ int32_t, uint16_t, EXTRACT16, EXTRACT8, INSERT16,
+ ELEMS_H, 2, 1, 8, PSIMD_MUL_SU32)
+
+GEN_PSIMD_MUL_HIGH_SEL(mulh_h0, uint32_t, int32_t, int16_t,
+ int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+ ELEMS_W, 0, 0, 16, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_SEL(mulh_h1, uint32_t, int32_t, int16_t,
+ int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+ ELEMS_W, 0, 1, 16, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_SEL(mulhsu_h0, uint32_t, int32_t, uint16_t,
+ int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+ ELEMS_W, 0, 0, 16, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_SEL(mulhsu_h1, uint32_t, int32_t, uint16_t,
+ int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+ ELEMS_W, 0, 1, 16, PSIMD_MUL_SU64)
+
+GEN_PSIMD_MUL_HIGH_SEL(pmulh_w_h0, uint64_t, int32_t, int16_t,
+ int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+ ELEMS_W, 2, 0, 16, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_SEL(pmulh_w_h1, uint64_t, int32_t, int16_t,
+ int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+ ELEMS_W, 2, 1, 16, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_SEL(pmulhsu_w_h0, uint64_t, int32_t, uint16_t,
+ int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+ ELEMS_W, 2, 0, 16, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_SEL(pmulhsu_w_h1, uint64_t, int32_t, uint16_t,
+ int64_t, uint32_t, EXTRACT32, EXTRACT16, INSERT32,
+ ELEMS_W, 2, 1, 16, PSIMD_MUL_SU64)
+
+GEN_PSIMD_MUL_ELEM_INDEXED(pmul_h_b00, target_ulong, int8_t, int8_t,
+ int16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+ 2, 0, 0, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmul_h_b01, target_ulong, int8_t, int8_t,
+ int16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+ 2, 0, 1, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmul_h_b11, target_ulong, int8_t, int8_t,
+ int16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+ 2, 1, 1, PSIMD_MUL_S32)
+
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulsu_h_b00, target_ulong, int8_t, uint8_t,
+ int16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+ 2, 0, 0, PSIMD_MUL_SU16)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulsu_h_b11, target_ulong, int8_t, uint8_t,
+ int16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+ 2, 1, 1, PSIMD_MUL_SU16)
+
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulu_h_b00, target_ulong, uint8_t, uint8_t,
+ uint16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+ 2, 0, 0, PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulu_h_b01, target_ulong, uint8_t, uint8_t,
+ uint16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+ 2, 0, 1, PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulu_h_b11, target_ulong, uint8_t, uint8_t,
+ uint16_t, uint16_t, EXTRACT8, INSERT16, ELEMS_H,
+ 2, 1, 1, PSIMD_MUL_U32)
+
+GEN_PSIMD_MUL_ELEM_INDEXED(pmul_w_h00, uint64_t, int16_t, int16_t,
+ int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+ 2, 0, 0, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmul_w_h01, uint64_t, int16_t, int16_t,
+ int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+ 2, 0, 1, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmul_w_h11, uint64_t, int16_t, int16_t,
+ int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+ 2, 1, 1, PSIMD_MUL_S32)
+
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulsu_w_h00, uint64_t, int16_t, uint16_t,
+ int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+ 2, 0, 0, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulsu_w_h11, uint64_t, int16_t, uint16_t,
+ int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+ 2, 1, 1, PSIMD_MUL_SU32)
+
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulu_w_h00, uint64_t, uint16_t, uint16_t,
+ uint32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+ 2, 0, 0, PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulu_w_h01, uint64_t, uint16_t, uint16_t,
+ uint32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+ 2, 0, 1, PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ELEM_INDEXED(pmulu_w_h11, uint64_t, uint16_t, uint16_t,
+ uint32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W,
+ 2, 1, 1, PSIMD_MUL_U32)
+
+GEN_PSIMD_2WAY_SAT_MUL(pm2sadd_h, 0, 1, 0, 1)
+GEN_PSIMD_2WAY_SAT_MUL(pm2sadd_hx, 0, 1, 1, 0)
+
+GEN_PSIMD_MUL_ELEM_SCALAR(mul_h00, uint32_t, int16_t, int16_t,
+ int32_t, EXTRACT16, 0, 0, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ELEM_SCALAR(mul_h01, uint32_t, int16_t, int16_t,
+ int32_t, EXTRACT16, 0, 1, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ELEM_SCALAR(mul_h11, uint32_t, int16_t, int16_t,
+ int32_t, EXTRACT16, 1, 1, PSIMD_MUL_S32)
+
+GEN_PSIMD_MUL_ELEM_SCALAR(mulsu_h00, uint32_t, int16_t, uint16_t,
+ int32_t, EXTRACT16, 0, 0, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_ELEM_SCALAR(mulsu_h11, uint32_t, int16_t, uint16_t,
+ int32_t, EXTRACT16, 1, 1, PSIMD_MUL_SU32)
+
+GEN_PSIMD_MUL_ELEM_SCALAR(mulu_h00, uint32_t, uint16_t, uint16_t,
+ uint32_t, EXTRACT16, 0, 0, PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ELEM_SCALAR(mulu_h01, uint32_t, uint16_t, uint16_t,
+ uint32_t, EXTRACT16, 0, 1, PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ELEM_SCALAR(mulu_h11, uint32_t, uint16_t, uint16_t,
+ uint32_t, EXTRACT16, 1, 1, PSIMD_MUL_U32)
+
+GEN_PSIMD_MUL_ELEM_SCALAR(mul_w00, uint64_t, int32_t, int32_t,
+ int64_t, EXTRACT32, 0, 0, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_ELEM_SCALAR(mul_w01, uint64_t, int32_t, int32_t,
+ int64_t, EXTRACT32, 0, 1, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_ELEM_SCALAR(mul_w11, uint64_t, int32_t, int32_t,
+ int64_t, EXTRACT32, 1, 1, PSIMD_MUL_S64)
+
+GEN_PSIMD_MUL_ELEM_SCALAR(mulsu_w00, uint64_t, int32_t, uint32_t,
+ int64_t, EXTRACT32, 0, 0, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_ELEM_SCALAR(mulsu_w11, uint64_t, int32_t, uint32_t,
+ int64_t, EXTRACT32, 1, 1, PSIMD_MUL_SU64)
+
+GEN_PSIMD_MUL_ELEM_SCALAR(mulu_w00, uint64_t, uint32_t, uint32_t,
+ uint64_t, EXTRACT32, 0, 0, PSIMD_MUL_U64)
+GEN_PSIMD_MUL_ELEM_SCALAR(mulu_w01, uint64_t, uint32_t, uint32_t,
+ uint64_t, EXTRACT32, 0, 1, PSIMD_MUL_U64)
+GEN_PSIMD_MUL_ELEM_SCALAR(mulu_w11, uint64_t, uint32_t, uint32_t,
+ uint64_t, EXTRACT32, 1, 1, PSIMD_MUL_U64)
+
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 11/18] target/riscv: Add packed SIMD multiply-accumulate instructions
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (9 preceding siblings ...)
2026-07-17 10:07 ` [PATCH v2 10/18] target/riscv: Add packed SIMD multiplication instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
2026-07-17 10:07 ` [PATCH v2 12/18] target/riscv: Add packed SIMD Q-format multiplication instructions Molly Chen
` (8 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/helper.h | 56 ++++++
target/riscv/insn32.decode | 92 +++++++++
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 56 ++++++
target/riscv/tcg/psimd_helper.c | 195 ++++++++++++++++++++
4 files changed, 399 insertions(+)
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index f06f40b1284..48604d91a79 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1624,3 +1624,59 @@ DEF_HELPER_3(mulsu_w11, i64, env, i64, i64)
DEF_HELPER_3(mulu_w00, i64, env, i64, i64)
DEF_HELPER_3(mulu_w01, i64, env, i64, i64)
DEF_HELPER_3(mulu_w11, i64, env, i64, i64)
+
+/* Packed SIMD - Multiply-Accumulate Operations */
+DEF_HELPER_4(pmhacc_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhaccsu_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhaccu_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhracc_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhraccsu_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhraccu_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhacc_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhracc_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhaccsu_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhraccsu_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhaccu_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhraccu_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(mhacc, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhracc, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhaccsu, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhraccsu, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhaccu, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhraccu, i32, env, i32, i32, i32)
+DEF_HELPER_4(pmhacc_h_b0, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhacc_h_b1, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhaccsu_h_b0, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmhaccsu_h_b1, tl, env, tl, tl, tl)
+DEF_HELPER_4(mhacc_h0, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhacc_h1, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhaccsu_h0, i32, env, i32, i32, i32)
+DEF_HELPER_4(mhaccsu_h1, i32, env, i32, i32, i32)
+DEF_HELPER_4(pmhacc_w_h0, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhacc_w_h1, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhaccsu_w_h0, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmhaccsu_w_h1, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmacc_w_h00, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmacc_w_h01, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmacc_w_h11, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmaccsu_w_h00, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmaccsu_w_h11, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmaccu_w_h00, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmaccu_w_h01, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmaccu_w_h11, i64, env, i64, i64, i64)
+DEF_HELPER_4(macc_h00, i32, env, i32, i32, i32)
+DEF_HELPER_4(macc_h01, i32, env, i32, i32, i32)
+DEF_HELPER_4(macc_h11, i32, env, i32, i32, i32)
+DEF_HELPER_4(maccsu_h00, i32, env, i32, i32, i32)
+DEF_HELPER_4(maccsu_h11, i32, env, i32, i32, i32)
+DEF_HELPER_4(maccu_h00, i32, env, i32, i32, i32)
+DEF_HELPER_4(maccu_h01, i32, env, i32, i32, i32)
+DEF_HELPER_4(maccu_h11, i32, env, i32, i32, i32)
+DEF_HELPER_4(macc_w00, i64, env, i64, i64, i64)
+DEF_HELPER_4(macc_w01, i64, env, i64, i64, i64)
+DEF_HELPER_4(macc_w11, i64, env, i64, i64, i64)
+DEF_HELPER_4(maccsu_w00, i64, env, i64, i64, i64)
+DEF_HELPER_4(maccsu_w11, i64, env, i64, i64, i64)
+DEF_HELPER_4(maccu_w00, i64, env, i64, i64, i64)
+DEF_HELPER_4(maccu_w01, i64, env, i64, i64, i64)
+DEF_HELPER_4(maccu_w11, i64, env, i64, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index cc0cc35fe24..a9b407e43e2 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1430,3 +1430,95 @@ mulsu_w11 11110 11 ..... ..... 011 ..... 0111011 @r
mulu_w00 10100 11 ..... ..... 011 ..... 0111011 @r
mulu_w01 10110 11 ..... ..... 001 ..... 0111011 @r
mulu_w11 10110 11 ..... ..... 011 ..... 0111011 @r
+
+# Packed SIMD - Multiply-Accumulate Operations
+pmhacc_h 10001 00 ..... ..... 111 ..... 0111011 @r
+pmhaccsu_h 11001 00 ..... ..... 111 ..... 0111011 @r
+pmhaccu_h 10011 00 ..... ..... 111 ..... 0111011 @r
+pmhracc_h 10001 10 ..... ..... 111 ..... 0111011 @r
+pmhraccsu_h 11001 10 ..... ..... 111 ..... 0111011 @r
+pmhraccu_h 10011 10 ..... ..... 111 ..... 0111011 @r
+{
+ mhacc 10001 01 ..... ..... 111 ..... 0111011 @r
+ pmhacc_w 10001 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+ mhracc 10001 11 ..... ..... 111 ..... 0111011 @r
+ pmhracc_w 10001 11 ..... ..... 111 ..... 0111011 @r
+}
+{
+ mhaccsu 11001 01 ..... ..... 111 ..... 0111011 @r
+ pmhaccsu_w 11001 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+ mhraccsu 11001 11 ..... ..... 111 ..... 0111011 @r
+ pmhraccsu_w 11001 11 ..... ..... 111 ..... 0111011 @r
+}
+{
+ mhaccu 10011 01 ..... ..... 111 ..... 0111011 @r
+ pmhaccu_w 10011 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+ mhraccu 10011 11 ..... ..... 111 ..... 0111011 @r
+ pmhraccu_w 10011 11 ..... ..... 111 ..... 0111011 @r
+}
+pmhacc_h_b0 10101 00 ..... ..... 111 ..... 0111011 @r
+pmhacc_h_b1 10111 00 ..... ..... 111 ..... 0111011 @r
+pmhaccsu_h_b0 10101 10 ..... ..... 111 ..... 0111011 @r
+pmhaccsu_h_b1 10111 10 ..... ..... 111 ..... 0111011 @r
+{
+ mhacc_h0 10101 01 ..... ..... 111 ..... 0111011 @r
+ pmhacc_w_h0 10101 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+ mhacc_h1 10111 01 ..... ..... 111 ..... 0111011 @r
+ pmhacc_w_h1 10111 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+ mhaccsu_h0 10101 11 ..... ..... 111 ..... 0111011 @r
+ pmhaccsu_w_h0 10101 11 ..... ..... 111 ..... 0111011 @r
+}
+{
+ mhaccsu_h1 10111 11 ..... ..... 111 ..... 0111011 @r
+ pmhaccsu_w_h1 10111 11 ..... ..... 111 ..... 0111011 @r
+}
+{
+ macc_h00 10001 01 ..... ..... 011 ..... 0111011 @r
+ pmacc_w_h00 10001 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+ macc_h01 10011 01 ..... ..... 001 ..... 0111011 @r
+ pmacc_w_h01 10011 01 ..... ..... 001 ..... 0111011 @r
+}
+{
+ macc_h11 10011 01 ..... ..... 011 ..... 0111011 @r
+ pmacc_w_h11 10011 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+ maccsu_h00 11101 01 ..... ..... 011 ..... 0111011 @r
+ pmaccsu_w_h00 11101 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+ maccsu_h11 11111 01 ..... ..... 011 ..... 0111011 @r
+ pmaccsu_w_h11 11111 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+ maccu_h00 10101 01 ..... ..... 011 ..... 0111011 @r
+ pmaccu_w_h00 10101 01 ..... ..... 011 ..... 0111011 @r
+}
+{
+ maccu_h01 10111 01 ..... ..... 001 ..... 0111011 @r
+ pmaccu_w_h01 10111 01 ..... ..... 001 ..... 0111011 @r
+}
+{
+ maccu_h11 10111 01 ..... ..... 011 ..... 0111011 @r
+ pmaccu_w_h11 10111 01 ..... ..... 011 ..... 0111011 @r
+}
+macc_w00 10001 11 ..... ..... 011 ..... 0111011 @r
+macc_w01 10011 11 ..... ..... 001 ..... 0111011 @r
+macc_w11 10011 11 ..... ..... 011 ..... 0111011 @r
+maccsu_w00 11101 11 ..... ..... 011 ..... 0111011 @r
+maccsu_w11 11111 11 ..... ..... 011 ..... 0111011 @r
+maccu_w00 10101 11 ..... ..... 011 ..... 0111011 @r
+maccu_w01 10111 11 ..... ..... 001 ..... 0111011 @r
+maccu_w11 10111 11 ..... ..... 011 ..... 0111011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 7edea099d01..5a30c49016f 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -770,3 +770,59 @@ GEN_SIMD_TRANS_64(mulu_w00)
GEN_SIMD_TRANS_64(mulu_w01)
GEN_SIMD_TRANS_64(mulu_w11)
+/* Packed SIMD - Multiply-Accumulate Operations */
+GEN_SIMD_TRANS_ACC(pmhacc_h)
+GEN_SIMD_TRANS_ACC(pmhaccsu_h)
+GEN_SIMD_TRANS_ACC(pmhaccu_h)
+GEN_SIMD_TRANS_ACC(pmhracc_h)
+GEN_SIMD_TRANS_ACC(pmhraccsu_h)
+GEN_SIMD_TRANS_ACC(pmhraccu_h)
+GEN_SIMD_TRANS_ACC_64(pmhacc_w)
+GEN_SIMD_TRANS_ACC_64(pmhracc_w)
+GEN_SIMD_TRANS_ACC_64(pmhaccsu_w)
+GEN_SIMD_TRANS_ACC_64(pmhraccsu_w)
+GEN_SIMD_TRANS_ACC_64(pmhaccu_w)
+GEN_SIMD_TRANS_ACC_64(pmhraccu_w)
+GEN_SIMD_TRANS_ACC_32(mhacc)
+GEN_SIMD_TRANS_ACC_32(mhracc)
+GEN_SIMD_TRANS_ACC_32(mhaccsu)
+GEN_SIMD_TRANS_ACC_32(mhraccsu)
+GEN_SIMD_TRANS_ACC_32(mhaccu)
+GEN_SIMD_TRANS_ACC_32(mhraccu)
+GEN_SIMD_TRANS_ACC(pmhacc_h_b0)
+GEN_SIMD_TRANS_ACC(pmhacc_h_b1)
+GEN_SIMD_TRANS_ACC(pmhaccsu_h_b0)
+GEN_SIMD_TRANS_ACC(pmhaccsu_h_b1)
+GEN_SIMD_TRANS_ACC_32(mhacc_h0)
+GEN_SIMD_TRANS_ACC_32(mhacc_h1)
+GEN_SIMD_TRANS_ACC_32(mhaccsu_h0)
+GEN_SIMD_TRANS_ACC_32(mhaccsu_h1)
+GEN_SIMD_TRANS_ACC_64(pmhacc_w_h0)
+GEN_SIMD_TRANS_ACC_64(pmhacc_w_h1)
+GEN_SIMD_TRANS_ACC_64(pmhaccsu_w_h0)
+GEN_SIMD_TRANS_ACC_64(pmhaccsu_w_h1)
+GEN_SIMD_TRANS_ACC_64(pmacc_w_h00)
+GEN_SIMD_TRANS_ACC_64(pmacc_w_h01)
+GEN_SIMD_TRANS_ACC_64(pmacc_w_h11)
+GEN_SIMD_TRANS_ACC_64(pmaccsu_w_h00)
+GEN_SIMD_TRANS_ACC_64(pmaccsu_w_h11)
+GEN_SIMD_TRANS_ACC_64(pmaccu_w_h00)
+GEN_SIMD_TRANS_ACC_64(pmaccu_w_h01)
+GEN_SIMD_TRANS_ACC_64(pmaccu_w_h11)
+GEN_SIMD_TRANS_ACC_32(macc_h00)
+GEN_SIMD_TRANS_ACC_32(macc_h01)
+GEN_SIMD_TRANS_ACC_32(macc_h11)
+GEN_SIMD_TRANS_ACC_32(maccsu_h00)
+GEN_SIMD_TRANS_ACC_32(maccsu_h11)
+GEN_SIMD_TRANS_ACC_32(maccu_h00)
+GEN_SIMD_TRANS_ACC_32(maccu_h01)
+GEN_SIMD_TRANS_ACC_32(maccu_h11)
+GEN_SIMD_TRANS_ACC_64(macc_w00)
+GEN_SIMD_TRANS_ACC_64(macc_w01)
+GEN_SIMD_TRANS_ACC_64(macc_w11)
+GEN_SIMD_TRANS_ACC_64(maccsu_w00)
+GEN_SIMD_TRANS_ACC_64(maccsu_w11)
+GEN_SIMD_TRANS_ACC_64(maccu_w00)
+GEN_SIMD_TRANS_ACC_64(maccu_w01)
+GEN_SIMD_TRANS_ACC_64(maccu_w11)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 5be8fe257f8..91a3aac3ebb 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2443,3 +2443,198 @@ GEN_PSIMD_MUL_ELEM_SCALAR(mulu_w01, uint64_t, uint32_t, uint32_t,
GEN_PSIMD_MUL_ELEM_SCALAR(mulu_w11, uint64_t, uint32_t, uint32_t,
uint64_t, EXTRACT32, 1, 1, PSIMD_MUL_U64)
+/* Multiply-Accumulate Operations */
+
+GEN_PSIMD_MUL_HIGH_ACC(pmhacc_h, target_ulong, int16_t, int16_t, int16_t,
+ int32_t, int16_t, uint16_t, EXTRACT16, INSERT16,
+ ELEMS_H, 16, 0, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH_ACC(pmhaccsu_h, target_ulong, int16_t, uint16_t, int16_t,
+ int32_t, int16_t, uint16_t, EXTRACT16, INSERT16,
+ ELEMS_H, 16, 0, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_HIGH_ACC(pmhaccu_h, target_ulong, uint16_t, uint16_t, uint16_t,
+ uint32_t, uint16_t, uint16_t, EXTRACT16, INSERT16,
+ ELEMS_H, 16, 0, PSIMD_MUL_U32)
+GEN_PSIMD_MUL_HIGH_ACC(pmhracc_h, target_ulong, int16_t, int16_t, int16_t,
+ int32_t, int16_t, uint16_t, EXTRACT16, INSERT16,
+ ELEMS_H, 16, 1 << 15, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH_ACC(pmhraccsu_h, target_ulong, int16_t, uint16_t, int16_t,
+ int32_t, int16_t, uint16_t, EXTRACT16, INSERT16,
+ ELEMS_H, 16, 1 << 15, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_HIGH_ACC(pmhraccu_h, target_ulong, uint16_t, uint16_t,
+ uint16_t, uint32_t, uint16_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, 16, 1 << 15,
+ PSIMD_MUL_U32)
+
+GEN_PSIMD_MUL_HIGH_ACC(pmhacc_w, uint64_t, int32_t, int32_t, int32_t,
+ int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+ ELEMS_W, 32, 0, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC(pmhracc_w, uint64_t, int32_t, int32_t, int32_t,
+ int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+ ELEMS_W, 32, 1LL << 31, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC(pmhaccsu_w, uint64_t, int32_t, uint32_t, int32_t,
+ int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+ ELEMS_W, 32, 0, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_ACC(pmhraccsu_w, uint64_t, int32_t, uint32_t, int32_t,
+ int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+ ELEMS_W, 32, 1LL << 31, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_ACC(pmhaccu_w, uint64_t, uint32_t, uint32_t, uint32_t,
+ uint64_t, uint32_t, uint32_t, EXTRACT32, INSERT32,
+ ELEMS_W, 32, 0, PSIMD_MUL_U64)
+GEN_PSIMD_MUL_HIGH_ACC(pmhraccu_w, uint64_t, uint32_t, uint32_t, uint32_t,
+ uint64_t, uint32_t, uint32_t, EXTRACT32, INSERT32,
+ ELEMS_W, 32, 1LL << 31, PSIMD_MUL_U64)
+
+GEN_PSIMD_MUL_HIGH_ACC(mhacc, uint32_t, int32_t, int32_t, int32_t,
+ int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+ ELEMS_W, 32, 0, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC(mhracc, uint32_t, int32_t, int32_t, int32_t,
+ int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+ ELEMS_W, 32, 1LL << 31, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC(mhaccsu, uint32_t, int32_t, uint32_t, int32_t,
+ int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+ ELEMS_W, 32, 0, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_ACC(mhraccsu, uint32_t, int32_t, uint32_t, int32_t,
+ int64_t, int32_t, uint32_t, EXTRACT32, INSERT32,
+ ELEMS_W, 32, 1LL << 31, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_ACC(mhaccu, uint32_t, uint32_t, uint32_t, uint32_t,
+ uint64_t, uint32_t, uint32_t, EXTRACT32, INSERT32,
+ ELEMS_W, 32, 0, PSIMD_MUL_U64)
+GEN_PSIMD_MUL_HIGH_ACC(mhraccu, uint32_t, uint32_t, uint32_t, uint32_t,
+ uint64_t, uint32_t, uint32_t, EXTRACT32, INSERT32,
+ ELEMS_W, 32, 1LL << 31, PSIMD_MUL_U64)
+
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhacc_h_b0, target_ulong, int16_t, int8_t,
+ int16_t, int32_t, int16_t, uint16_t, EXTRACT16,
+ EXTRACT8, INSERT16, ELEMS_H, 2, 0, 8,
+ PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhacc_h_b1, target_ulong, int16_t, int8_t,
+ int16_t, int32_t, int16_t, uint16_t, EXTRACT16,
+ EXTRACT8, INSERT16, ELEMS_H, 2, 1, 8,
+ PSIMD_MUL_S32)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhaccsu_h_b0, target_ulong, int16_t, uint8_t,
+ int16_t, int32_t, int16_t, uint16_t, EXTRACT16,
+ EXTRACT8, INSERT16, ELEMS_H, 2, 0, 8,
+ PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhaccsu_h_b1, target_ulong, int16_t, uint8_t,
+ int16_t, int32_t, int16_t, uint16_t, EXTRACT16,
+ EXTRACT8, INSERT16, ELEMS_H, 2, 1, 8,
+ PSIMD_MUL_SU32)
+
+GEN_PSIMD_MUL_HIGH_ACC_SEL(mhacc_h0, uint32_t, int32_t, int16_t, int32_t,
+ int64_t, int32_t, uint32_t, EXTRACT32,
+ EXTRACT16, INSERT32, ELEMS_W, 0, 0, 16,
+ PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(mhacc_h1, uint32_t, int32_t, int16_t, int32_t,
+ int64_t, int32_t, uint32_t, EXTRACT32,
+ EXTRACT16, INSERT32, ELEMS_W, 0, 1, 16,
+ PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(mhaccsu_h0, uint32_t, int32_t, uint16_t, int32_t,
+ int64_t, int32_t, uint32_t, EXTRACT32,
+ EXTRACT16, INSERT32, ELEMS_W, 0, 0, 16,
+ PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(mhaccsu_h1, uint32_t, int32_t, uint16_t, int32_t,
+ int64_t, int32_t, uint32_t, EXTRACT32,
+ EXTRACT16, INSERT32, ELEMS_W, 0, 1, 16,
+ PSIMD_MUL_SU64)
+
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhacc_w_h0, uint64_t, int32_t, int16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT32,
+ EXTRACT16, INSERT32, ELEMS_W, 2, 0, 16,
+ PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhacc_w_h1, uint64_t, int32_t, int16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT32,
+ EXTRACT16, INSERT32, ELEMS_W, 2, 1, 16,
+ PSIMD_MUL_S64)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhaccsu_w_h0, uint64_t, int32_t, uint16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT32,
+ EXTRACT16, INSERT32, ELEMS_W, 2, 0, 16,
+ PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_HIGH_ACC_SEL(pmhaccsu_w_h1, uint64_t, int32_t, uint16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT32,
+ EXTRACT16, INSERT32, ELEMS_W, 2, 1, 16,
+ PSIMD_MUL_SU64)
+
+GEN_PSIMD_MUL_ACC_INDEXED(pmacc_w_h00, uint64_t, int16_t, int16_t,
+ int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 2, 0, 0, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ACC_INDEXED(pmacc_w_h01, uint64_t, int16_t, int16_t,
+ int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 2, 0, 1, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ACC_INDEXED(pmacc_w_h11, uint64_t, int16_t, int16_t,
+ int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 2, 1, 1, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ACC_INDEXED(pmaccsu_w_h00, uint64_t, int16_t, uint16_t,
+ int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 2, 0, 0, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_ACC_INDEXED(pmaccsu_w_h11, uint64_t, int16_t, uint16_t,
+ int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 2, 1, 1, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_ACC_INDEXED(pmaccu_w_h00, uint64_t, uint16_t, uint16_t,
+ uint32_t, uint32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 2, 0, 0,
+ PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ACC_INDEXED(pmaccu_w_h01, uint64_t, uint16_t, uint16_t,
+ uint32_t, uint32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 2, 0, 1,
+ PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ACC_INDEXED(pmaccu_w_h11, uint64_t, uint16_t, uint16_t,
+ uint32_t, uint32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 2, 1, 1,
+ PSIMD_MUL_U32)
+
+GEN_PSIMD_MUL_ACC_INDEXED(macc_h00, uint32_t, int16_t, int16_t,
+ int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 0, 0, 0, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ACC_INDEXED(macc_h01, uint32_t, int16_t, int16_t,
+ int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 0, 0, 1, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ACC_INDEXED(macc_h11, uint32_t, int16_t, int16_t,
+ int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 0, 1, 1, PSIMD_MUL_S32)
+GEN_PSIMD_MUL_ACC_INDEXED(maccsu_h00, uint32_t, int16_t, uint16_t,
+ int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 0, 0, 0, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_ACC_INDEXED(maccsu_h11, uint32_t, int16_t, uint16_t,
+ int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 0, 1, 1, PSIMD_MUL_SU32)
+GEN_PSIMD_MUL_ACC_INDEXED(maccu_h00, uint32_t, uint16_t, uint16_t,
+ uint32_t, uint32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 0, 0, 0,
+ PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ACC_INDEXED(maccu_h01, uint32_t, uint16_t, uint16_t,
+ uint32_t, uint32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 0, 0, 1,
+ PSIMD_MUL_U32)
+GEN_PSIMD_MUL_ACC_INDEXED(maccu_h11, uint32_t, uint16_t, uint16_t,
+ uint32_t, uint32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 0, 1, 1,
+ PSIMD_MUL_U32)
+
+GEN_PSIMD_MUL_ACC_INDEXED(macc_w00, uint64_t, int32_t, int32_t,
+ int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+ INSERT64, ELEMS_D, 0, 0, 0, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_ACC_INDEXED(macc_w01, uint64_t, int32_t, int32_t,
+ int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+ INSERT64, ELEMS_D, 0, 0, 1, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_ACC_INDEXED(macc_w11, uint64_t, int32_t, int32_t,
+ int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+ INSERT64, ELEMS_D, 0, 1, 1, PSIMD_MUL_S64)
+GEN_PSIMD_MUL_ACC_INDEXED(maccsu_w00, uint64_t, int32_t, uint32_t,
+ int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+ INSERT64, ELEMS_D, 0, 0, 0, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_ACC_INDEXED(maccsu_w11, uint64_t, int32_t, uint32_t,
+ int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+ INSERT64, ELEMS_D, 0, 1, 1, PSIMD_MUL_SU64)
+GEN_PSIMD_MUL_ACC_INDEXED(maccu_w00, uint64_t, uint32_t, uint32_t,
+ uint64_t, uint64_t, uint64_t, EXTRACT32,
+ EXTRACT64, INSERT64, ELEMS_D, 0, 0, 0,
+ PSIMD_MUL_U64)
+GEN_PSIMD_MUL_ACC_INDEXED(maccu_w01, uint64_t, uint32_t, uint32_t,
+ uint64_t, uint64_t, uint64_t, EXTRACT32,
+ EXTRACT64, INSERT64, ELEMS_D, 0, 0, 1,
+ PSIMD_MUL_U64)
+GEN_PSIMD_MUL_ACC_INDEXED(maccu_w11, uint64_t, uint32_t, uint32_t,
+ uint64_t, uint64_t, uint64_t, EXTRACT32,
+ EXTRACT64, INSERT64, ELEMS_D, 0, 1, 1,
+ PSIMD_MUL_U64)
+
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 12/18] target/riscv: Add packed SIMD Q-format multiplication instructions
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (10 preceding siblings ...)
2026-07-17 10:07 ` [PATCH v2 11/18] target/riscv: Add packed SIMD multiply-accumulate instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
2026-07-17 10:07 ` [PATCH v2 13/18] target/riscv: Add packed SIMD Q-format MAC instructions Molly Chen
` (7 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/helper.h | 8 ++++++++
target/riscv/insn32.decode | 12 ++++++++++++
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 8 ++++++++
target/riscv/tcg/psimd_helper.c | 17 +++++++++++++++++
4 files changed, 45 insertions(+)
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 48604d91a79..638c7b0629d 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1680,3 +1680,11 @@ DEF_HELPER_4(maccsu_w11, i64, env, i64, i64, i64)
DEF_HELPER_4(maccu_w00, i64, env, i64, i64, i64)
DEF_HELPER_4(maccu_w01, i64, env, i64, i64, i64)
DEF_HELPER_4(maccu_w11, i64, env, i64, i64, i64)
+
+/* Packed SIMD - Q-Format Multiplication Operations */
+DEF_HELPER_3(pmulq_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulqr_h, tl, env, tl, tl)
+DEF_HELPER_3(pmulq_w, i64, env, i64, i64)
+DEF_HELPER_3(pmulqr_w, i64, env, i64, i64)
+DEF_HELPER_3(mulq, i32, env, i32, i32)
+DEF_HELPER_3(mulqr, i32, env, i32, i32)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index a9b407e43e2..9c50a4dbf52 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1522,3 +1522,15 @@ maccsu_w11 11111 11 ..... ..... 011 ..... 0111011 @r
maccu_w00 10101 11 ..... ..... 011 ..... 0111011 @r
maccu_w01 10111 11 ..... ..... 001 ..... 0111011 @r
maccu_w11 10111 11 ..... ..... 011 ..... 0111011 @r
+
+# Packed SIMD - Q-Format Multiplication Operations
+pmulq_h 11010 00 ..... ..... 111 ..... 0111011 @r
+pmulqr_h 11010 10 ..... ..... 111 ..... 0111011 @r
+{
+ mulq 11010 01 ..... ..... 111 ..... 0111011 @r
+ pmulq_w 11010 01 ..... ..... 111 ..... 0111011 @r
+}
+{
+ mulqr 11010 11 ..... ..... 111 ..... 0111011 @r
+ pmulqr_w 11010 11 ..... ..... 111 ..... 0111011 @r
+}
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 5a30c49016f..3535f71de88 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -826,3 +826,11 @@ GEN_SIMD_TRANS_ACC_64(maccu_w00)
GEN_SIMD_TRANS_ACC_64(maccu_w01)
GEN_SIMD_TRANS_ACC_64(maccu_w11)
+/* Packed SIMD - Q-Format Multiplication Operations */
+GEN_SIMD_TRANS_VXSAT(pmulq_h)
+GEN_SIMD_TRANS_VXSAT(pmulqr_h)
+GEN_SIMD_TRANS_64_VXSAT(pmulq_w)
+GEN_SIMD_TRANS_64_VXSAT(pmulqr_w)
+GEN_SIMD_TRANS_32_VXSAT(mulq)
+GEN_SIMD_TRANS_32_VXSAT(mulqr)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 91a3aac3ebb..11ca17576be 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2638,3 +2638,20 @@ GEN_PSIMD_MUL_ACC_INDEXED(maccu_w11, uint64_t, uint32_t, uint32_t,
EXTRACT64, INSERT64, ELEMS_D, 0, 1, 1,
PSIMD_MUL_U64)
+/* Q-Format Multiplication Operations */
+
+GEN_PSIMD_QMUL(pmulq_h, target_ulong, int16_t, int32_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, 15, 0, INT16_MIN, INT16_MAX)
+GEN_PSIMD_QMUL(pmulqr_h, target_ulong, int16_t, int32_t, uint16_t,
+ EXTRACT16, INSERT16, ELEMS_H, 15, 1 << 14, INT16_MIN,
+ INT16_MAX)
+GEN_PSIMD_QMUL(pmulq_w, uint64_t, int32_t, int64_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 31, 0, INT32_MIN, INT32_MAX)
+GEN_PSIMD_QMUL(pmulqr_w, uint64_t, int32_t, int64_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 31, 1LL << 30, INT32_MIN,
+ INT32_MAX)
+GEN_PSIMD_QMUL(mulq, uint32_t, int32_t, int64_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 31, 0, INT32_MIN, INT32_MAX)
+GEN_PSIMD_QMUL(mulqr, uint32_t, int32_t, int64_t, uint32_t,
+ EXTRACT32, INSERT32, ELEMS_W, 31, 1LL << 30, INT32_MIN,
+ INT32_MAX)
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 13/18] target/riscv: Add packed SIMD Q-format MAC instructions
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (11 preceding siblings ...)
2026-07-17 10:07 ` [PATCH v2 12/18] target/riscv: Add packed SIMD Q-format multiplication instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
2026-07-17 10:07 ` [PATCH v2 14/18] target/riscv: Add packed SIMD two-way " Molly Chen
` (6 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/helper.h | 20 ++++++
target/riscv/insn32.decode | 32 +++++++++
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 20 ++++++
target/riscv/tcg/psimd_helper.c | 78 +++++++++++++++++++++
4 files changed, 150 insertions(+)
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 638c7b0629d..9568a7f91c4 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1688,3 +1688,23 @@ DEF_HELPER_3(pmulq_w, i64, env, i64, i64)
DEF_HELPER_3(pmulqr_w, i64, env, i64, i64)
DEF_HELPER_3(mulq, i32, env, i32, i32)
DEF_HELPER_3(mulqr, i32, env, i32, i32)
+
+/* Packed SIMD - Q-Format Multiply-Accumulate Operations */
+DEF_HELPER_4(mqacc_h00, i32, env, i32, i32, i32)
+DEF_HELPER_4(mqacc_h01, i32, env, i32, i32, i32)
+DEF_HELPER_4(mqacc_h11, i32, env, i32, i32, i32)
+DEF_HELPER_4(mqracc_h00, i32, env, i32, i32, i32)
+DEF_HELPER_4(mqracc_h01, i32, env, i32, i32, i32)
+DEF_HELPER_4(mqracc_h11, i32, env, i32, i32, i32)
+DEF_HELPER_4(mqacc_w00, i64, env, i64, i64, i64)
+DEF_HELPER_4(mqacc_w01, i64, env, i64, i64, i64)
+DEF_HELPER_4(mqacc_w11, i64, env, i64, i64, i64)
+DEF_HELPER_4(mqracc_w00, i64, env, i64, i64, i64)
+DEF_HELPER_4(mqracc_w01, i64, env, i64, i64, i64)
+DEF_HELPER_4(mqracc_w11, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmqacc_w_h00, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmqacc_w_h01, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmqacc_w_h11, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmqracc_w_h00, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmqracc_w_h01, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmqracc_w_h11, i64, env, i64, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 9c50a4dbf52..e2af5f83965 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1534,3 +1534,35 @@ pmulqr_h 11010 10 ..... ..... 111 ..... 0111011 @r
mulqr 11010 11 ..... ..... 111 ..... 0111011 @r
pmulqr_w 11010 11 ..... ..... 111 ..... 0111011 @r
}
+
+# Packed SIMD - Q-Format Multiply-Accumulate Operations
+{
+ mqacc_h00 11101 00 ..... ..... 111 ..... 0111011 @r
+ pmqacc_w_h00 11101 00 ..... ..... 111 ..... 0111011 @r
+}
+{
+ mqacc_h01 11111 00 ..... ..... 101 ..... 0111011 @r
+ pmqacc_w_h01 11111 00 ..... ..... 101 ..... 0111011 @r
+}
+{
+ mqacc_h11 11111 00 ..... ..... 111 ..... 0111011 @r
+ pmqacc_w_h11 11111 00 ..... ..... 111 ..... 0111011 @r
+}
+{
+ mqracc_h00 11101 10 ..... ..... 111 ..... 0111011 @r
+ pmqracc_w_h00 11101 10 ..... ..... 111 ..... 0111011 @r
+}
+{
+ mqracc_h01 11111 10 ..... ..... 101 ..... 0111011 @r
+ pmqracc_w_h01 11111 10 ..... ..... 101 ..... 0111011 @r
+}
+{
+ mqracc_h11 11111 10 ..... ..... 111 ..... 0111011 @r
+ pmqracc_w_h11 11111 10 ..... ..... 111 ..... 0111011 @r
+}
+mqacc_w00 11101 01 ..... ..... 111 ..... 0111011 @r
+mqacc_w01 11111 01 ..... ..... 101 ..... 0111011 @r
+mqacc_w11 11111 01 ..... ..... 111 ..... 0111011 @r
+mqracc_w00 11101 11 ..... ..... 111 ..... 0111011 @r
+mqracc_w01 11111 11 ..... ..... 101 ..... 0111011 @r
+mqracc_w11 11111 11 ..... ..... 111 ..... 0111011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 3535f71de88..cec18255a1e 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -834,3 +834,23 @@ GEN_SIMD_TRANS_64_VXSAT(pmulqr_w)
GEN_SIMD_TRANS_32_VXSAT(mulq)
GEN_SIMD_TRANS_32_VXSAT(mulqr)
+/* Packed SIMD - Q-Format Multiply-Accumulate Operations */
+GEN_SIMD_TRANS_ACC_32(mqacc_h00)
+GEN_SIMD_TRANS_ACC_32(mqacc_h01)
+GEN_SIMD_TRANS_ACC_32(mqacc_h11)
+GEN_SIMD_TRANS_ACC_32(mqracc_h00)
+GEN_SIMD_TRANS_ACC_32(mqracc_h01)
+GEN_SIMD_TRANS_ACC_32(mqracc_h11)
+GEN_SIMD_TRANS_ACC_64(mqacc_w00)
+GEN_SIMD_TRANS_ACC_64(mqacc_w01)
+GEN_SIMD_TRANS_ACC_64(mqacc_w11)
+GEN_SIMD_TRANS_ACC_64(mqracc_w00)
+GEN_SIMD_TRANS_ACC_64(mqracc_w01)
+GEN_SIMD_TRANS_ACC_64(mqracc_w11)
+GEN_SIMD_TRANS_ACC_64(pmqacc_w_h00)
+GEN_SIMD_TRANS_ACC_64(pmqacc_w_h01)
+GEN_SIMD_TRANS_ACC_64(pmqacc_w_h11)
+GEN_SIMD_TRANS_ACC_64(pmqracc_w_h00)
+GEN_SIMD_TRANS_ACC_64(pmqracc_w_h01)
+GEN_SIMD_TRANS_ACC_64(pmqracc_w_h11)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index 11ca17576be..ecdb20bbb58 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2655,3 +2655,81 @@ GEN_PSIMD_QMUL(mulq, uint32_t, int32_t, int64_t, uint32_t,
GEN_PSIMD_QMUL(mulqr, uint32_t, int32_t, int64_t, uint32_t,
EXTRACT32, INSERT32, ELEMS_W, 31, 1LL << 30, INT32_MIN,
INT32_MAX)
+
+
+/* Q-Format Multiply-Accumulate Operations */
+
+GEN_PSIMD_QMUL_ACC_INDEXED(mqacc_h00, uint32_t, int16_t, int16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 0, 0, 0, 15, 0,
+ PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqacc_h01, uint32_t, int16_t, int16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 0, 0, 1, 15, 0,
+ PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqacc_h11, uint32_t, int16_t, int16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 0, 1, 1, 15, 0,
+ PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqracc_h00, uint32_t, int16_t, int16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 0, 0, 0, 15,
+ 1LL << 14, PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqracc_h01, uint32_t, int16_t, int16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 0, 0, 1, 15,
+ 1LL << 14, PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqracc_h11, uint32_t, int16_t, int16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 0, 1, 1, 15,
+ 1LL << 14, PSIMD_MUL_S64)
+
+GEN_PSIMD_QMUL_ACC_INDEXED(mqacc_w00, uint64_t, int32_t, int32_t,
+ int64_t, int64_t, int64_t, uint64_t, EXTRACT32,
+ EXTRACT64, INSERT64, ELEMS_D, 0, 0, 0, 31, 0,
+ PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqacc_w01, uint64_t, int32_t, int32_t,
+ int64_t, int64_t, int64_t, uint64_t, EXTRACT32,
+ EXTRACT64, INSERT64, ELEMS_D, 0, 0, 1, 31, 0,
+ PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqacc_w11, uint64_t, int32_t, int32_t,
+ int64_t, int64_t, int64_t, uint64_t, EXTRACT32,
+ EXTRACT64, INSERT64, ELEMS_D, 0, 1, 1, 31, 0,
+ PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqracc_w00, uint64_t, int32_t, int32_t,
+ int64_t, int64_t, int64_t, uint64_t, EXTRACT32,
+ EXTRACT64, INSERT64, ELEMS_D, 0, 0, 0, 31,
+ 1LL << 30, PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqracc_w01, uint64_t, int32_t, int32_t,
+ int64_t, int64_t, int64_t, uint64_t, EXTRACT32,
+ EXTRACT64, INSERT64, ELEMS_D, 0, 0, 1, 31,
+ 1LL << 30, PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(mqracc_w11, uint64_t, int32_t, int32_t,
+ int64_t, int64_t, int64_t, uint64_t, EXTRACT32,
+ EXTRACT64, INSERT64, ELEMS_D, 0, 1, 1, 31,
+ 1LL << 30, PSIMD_MUL_S64)
+
+GEN_PSIMD_QMUL_ACC_INDEXED(pmqacc_w_h00, uint64_t, int16_t, int16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 2, 0, 0, 15, 0,
+ PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(pmqacc_w_h01, uint64_t, int16_t, int16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 2, 0, 1, 15, 0,
+ PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(pmqacc_w_h11, uint64_t, int16_t, int16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 2, 1, 1, 15, 0,
+ PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(pmqracc_w_h00, uint64_t, int16_t, int16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 2, 0, 0, 15,
+ 1LL << 14, PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(pmqracc_w_h01, uint64_t, int16_t, int16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 2, 0, 1, 15,
+ 1LL << 14, PSIMD_MUL_S64)
+GEN_PSIMD_QMUL_ACC_INDEXED(pmqracc_w_h11, uint64_t, int16_t, int16_t,
+ int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
+ EXTRACT32, INSERT32, ELEMS_W, 2, 1, 1, 15,
+ 1LL << 14, PSIMD_MUL_S64)
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 14/18] target/riscv: Add packed SIMD two-way MAC instructions
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (12 preceding siblings ...)
2026-07-17 10:07 ` [PATCH v2 13/18] target/riscv: Add packed SIMD Q-format MAC instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
2026-07-17 10:07 ` [PATCH v2 15/18] target/riscv: Add packed SIMD four-way " Molly Chen
` (5 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/helper.h | 34 ++++++
target/riscv/insn32.decode | 34 ++++++
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 34 ++++++
target/riscv/tcg/psimd_helper.c | 116 ++++++++++++++++++++
4 files changed, 218 insertions(+)
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 9568a7f91c4..b0743d19177 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1708,3 +1708,37 @@ DEF_HELPER_4(pmqacc_w_h11, i64, env, i64, i64, i64)
DEF_HELPER_4(pmqracc_w_h00, i64, env, i64, i64, i64)
DEF_HELPER_4(pmqracc_w_h01, i64, env, i64, i64, i64)
DEF_HELPER_4(pmqracc_w_h11, i64, env, i64, i64, i64)
+
+/* Packed SIMD - Two-Way Multiply and Accumulate Operations */
+DEF_HELPER_3(pmq2add_h, tl, env, tl, tl)
+DEF_HELPER_3(pmqr2add_h, tl, env, tl, tl)
+DEF_HELPER_4(pmq2adda_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pmqr2adda_h, tl, env, tl, tl, tl)
+DEF_HELPER_3(pmq2add_w, i64, env, i64, i64)
+DEF_HELPER_3(pmqr2add_w, i64, env, i64, i64)
+DEF_HELPER_4(pmq2adda_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pmqr2adda_w, i64, env, i64, i64, i64)
+DEF_HELPER_3(pm2add_h, tl, env, tl, tl)
+DEF_HELPER_3(pm2addsu_h, tl, env, tl, tl)
+DEF_HELPER_3(pm2addu_h, tl, env, tl, tl)
+DEF_HELPER_3(pm2add_hx, tl, env, tl, tl)
+DEF_HELPER_3(pm2sub_h, tl, env, tl, tl)
+DEF_HELPER_3(pm2sub_hx, tl, env, tl, tl)
+DEF_HELPER_4(pm2adda_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pm2addasu_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pm2addau_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pm2adda_hx, tl, env, tl, tl, tl)
+DEF_HELPER_4(pm2suba_h, tl, env, tl, tl, tl)
+DEF_HELPER_4(pm2suba_hx, tl, env, tl, tl, tl)
+DEF_HELPER_3(pm2add_w, i64, env, i64, i64)
+DEF_HELPER_3(pm2addsu_w, i64, env, i64, i64)
+DEF_HELPER_3(pm2addu_w, i64, env, i64, i64)
+DEF_HELPER_3(pm2add_wx, i64, env, i64, i64)
+DEF_HELPER_3(pm2sub_w, i64, env, i64, i64)
+DEF_HELPER_3(pm2sub_wx, i64, env, i64, i64)
+DEF_HELPER_4(pm2adda_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pm2addasu_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pm2addau_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pm2adda_wx, i64, env, i64, i64, i64)
+DEF_HELPER_4(pm2suba_w, i64, env, i64, i64, i64)
+DEF_HELPER_4(pm2suba_wx, i64, env, i64, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index e2af5f83965..1c8bdde25c2 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1566,3 +1566,37 @@ mqacc_w11 11111 01 ..... ..... 111 ..... 0111011 @r
mqracc_w00 11101 11 ..... ..... 111 ..... 0111011 @r
mqracc_w01 11111 11 ..... ..... 101 ..... 0111011 @r
mqracc_w11 11111 11 ..... ..... 111 ..... 0111011 @r
+
+# Packed SIMD - Two-Way Multiply and Accumulate Operations
+pmq2add_h 10110 00 ..... ..... 101 ..... 0111011 @r
+pmqr2add_h 10110 10 ..... ..... 101 ..... 0111011 @r
+pmq2adda_h 10111 00 ..... ..... 101 ..... 0111011 @r
+pmqr2adda_h 10111 10 ..... ..... 101 ..... 0111011 @r
+pmq2add_w 10110 01 ..... ..... 101 ..... 0111011 @r
+pmqr2add_w 10110 11 ..... ..... 101 ..... 0111011 @r
+pmq2adda_w 10111 01 ..... ..... 101 ..... 0111011 @r
+pmqr2adda_w 10111 11 ..... ..... 101 ..... 0111011 @r
+pm2add_h 10000 00 ..... ..... 101 ..... 0111011 @r
+pm2addsu_h 11100 00 ..... ..... 101 ..... 0111011 @r
+pm2addu_h 10100 00 ..... ..... 101 ..... 0111011 @r
+pm2add_hx 10010 00 ..... ..... 101 ..... 0111011 @r
+pm2sub_h 11000 00 ..... ..... 101 ..... 0111011 @r
+pm2sub_hx 11010 00 ..... ..... 101 ..... 0111011 @r
+pm2adda_h 10001 00 ..... ..... 101 ..... 0111011 @r
+pm2addasu_h 11101 00 ..... ..... 101 ..... 0111011 @r
+pm2addau_h 10101 00 ..... ..... 101 ..... 0111011 @r
+pm2adda_hx 10011 00 ..... ..... 101 ..... 0111011 @r
+pm2suba_h 11001 00 ..... ..... 101 ..... 0111011 @r
+pm2suba_hx 11011 00 ..... ..... 101 ..... 0111011 @r
+pm2add_w 10000 01 ..... ..... 101 ..... 0111011 @r
+pm2addsu_w 11100 01 ..... ..... 101 ..... 0111011 @r
+pm2addu_w 10100 01 ..... ..... 101 ..... 0111011 @r
+pm2add_wx 10010 01 ..... ..... 101 ..... 0111011 @r
+pm2sub_w 11000 01 ..... ..... 101 ..... 0111011 @r
+pm2sub_wx 11010 01 ..... ..... 101 ..... 0111011 @r
+pm2adda_w 10001 01 ..... ..... 101 ..... 0111011 @r
+pm2addasu_w 11101 01 ..... ..... 101 ..... 0111011 @r
+pm2addau_w 10101 01 ..... ..... 101 ..... 0111011 @r
+pm2adda_wx 10011 01 ..... ..... 101 ..... 0111011 @r
+pm2suba_w 11001 01 ..... ..... 101 ..... 0111011 @r
+pm2suba_wx 11011 01 ..... ..... 101 ..... 0111011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index cec18255a1e..cf670b144c3 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -854,3 +854,37 @@ GEN_SIMD_TRANS_ACC_64(pmqracc_w_h00)
GEN_SIMD_TRANS_ACC_64(pmqracc_w_h01)
GEN_SIMD_TRANS_ACC_64(pmqracc_w_h11)
+/* Packed SIMD - Two-Way Multiply and Accumulate Operations */
+GEN_SIMD_TRANS(pmq2add_h)
+GEN_SIMD_TRANS(pmqr2add_h)
+GEN_SIMD_TRANS_ACC(pmq2adda_h)
+GEN_SIMD_TRANS_ACC(pmqr2adda_h)
+GEN_SIMD_TRANS_64(pmq2add_w)
+GEN_SIMD_TRANS_64(pmqr2add_w)
+GEN_SIMD_TRANS_ACC_64(pmq2adda_w)
+GEN_SIMD_TRANS_ACC_64(pmqr2adda_w)
+GEN_SIMD_TRANS(pm2add_h)
+GEN_SIMD_TRANS(pm2addsu_h)
+GEN_SIMD_TRANS(pm2addu_h)
+GEN_SIMD_TRANS(pm2add_hx)
+GEN_SIMD_TRANS(pm2sub_h)
+GEN_SIMD_TRANS(pm2sub_hx)
+GEN_SIMD_TRANS_ACC(pm2adda_h)
+GEN_SIMD_TRANS_ACC(pm2addasu_h)
+GEN_SIMD_TRANS_ACC(pm2addau_h)
+GEN_SIMD_TRANS_ACC(pm2adda_hx)
+GEN_SIMD_TRANS_ACC(pm2suba_h)
+GEN_SIMD_TRANS_ACC(pm2suba_hx)
+GEN_SIMD_TRANS_64(pm2add_w)
+GEN_SIMD_TRANS_64(pm2addsu_w)
+GEN_SIMD_TRANS_64(pm2addu_w)
+GEN_SIMD_TRANS_64(pm2add_wx)
+GEN_SIMD_TRANS_64(pm2sub_w)
+GEN_SIMD_TRANS_64(pm2sub_wx)
+GEN_SIMD_TRANS_ACC_64(pm2adda_w)
+GEN_SIMD_TRANS_ACC_64(pm2addasu_w)
+GEN_SIMD_TRANS_ACC_64(pm2addau_w)
+GEN_SIMD_TRANS_ACC_64(pm2adda_wx)
+GEN_SIMD_TRANS_ACC_64(pm2suba_w)
+GEN_SIMD_TRANS_ACC_64(pm2suba_wx)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index ecdb20bbb58..bad04937b54 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2733,3 +2733,119 @@ GEN_PSIMD_QMUL_ACC_INDEXED(pmqracc_w_h11, uint64_t, int16_t, int16_t,
int32_t, int64_t, int32_t, uint32_t, EXTRACT16,
EXTRACT32, INSERT32, ELEMS_W, 2, 1, 1, 15,
1LL << 14, PSIMD_MUL_S64)
+
+/* Two-Way Multiply and Accumulate Operations */
+
+GEN_PSIMD_Q2ADD(pmq2add_h, target_ulong, int16_t, int32_t, int64_t,
+ uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2, 15, 0,
+ PSIMD_MUL_S32)
+GEN_PSIMD_Q2ADD(pmqr2add_h, target_ulong, int16_t, int32_t, int64_t,
+ uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2, 15, 1LL << 14,
+ PSIMD_MUL_S32)
+GEN_PSIMD_Q2ADDA(pmq2adda_h, target_ulong, int16_t, int32_t, int32_t,
+ int64_t, uint32_t, EXTRACT16, EXTRACT32, INSERT32,
+ ELEMS_W, 2, 15, 0, PSIMD_MUL_S32)
+GEN_PSIMD_Q2ADDA(pmqr2adda_h, target_ulong, int16_t, int32_t, int32_t,
+ int64_t, uint32_t, EXTRACT16, EXTRACT32, INSERT32,
+ ELEMS_W, 2, 15, 1LL << 14, PSIMD_MUL_S32)
+
+GEN_PSIMD_Q2ADD(pmq2add_w, uint64_t, int32_t, int64_t, int64_t,
+ uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0, 31, 0,
+ PSIMD_MUL_S64)
+GEN_PSIMD_Q2ADD(pmqr2add_w, uint64_t, int32_t, int64_t, int64_t,
+ uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0, 31, 1LL << 30,
+ PSIMD_MUL_S64)
+GEN_PSIMD_Q2ADDA(pmq2adda_w, uint64_t, int32_t, int64_t, int64_t,
+ int64_t, uint64_t, EXTRACT32, EXTRACT64, INSERT64,
+ ELEMS_D, 0, 31, 0, PSIMD_MUL_S64)
+GEN_PSIMD_Q2ADDA(pmqr2adda_w, uint64_t, int32_t, int64_t, int64_t,
+ int64_t, uint64_t, EXTRACT32, EXTRACT64, INSERT64,
+ ELEMS_D, 0, 31, 1LL << 30, PSIMD_MUL_S64)
+
+GEN_PSIMD_2WAY_MUL(pm2add_h, target_ulong, int16_t, int16_t,
+ int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2,
+ 0, 1, 0, 1, PSIMD_MUL_S32, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2addsu_h, target_ulong, int16_t, uint16_t,
+ int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2,
+ 0, 1, 0, 1, PSIMD_MUL_SU32, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2addu_h, target_ulong, uint16_t, uint16_t,
+ uint32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2,
+ 0, 1, 0, 1, PSIMD_MUL_U32, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2add_hx, target_ulong, int16_t, int16_t,
+ int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2,
+ 0, 1, 1, 0, PSIMD_MUL_S32, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2sub_h, target_ulong, int16_t, int16_t,
+ int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2,
+ 0, 1, 0, 1, PSIMD_MUL_S32, PSIMD_COMB_SUB)
+GEN_PSIMD_2WAY_MUL(pm2sub_hx, target_ulong, int16_t, int16_t,
+ int32_t, uint32_t, EXTRACT16, INSERT32, ELEMS_W, 2,
+ 0, 1, 1, 0, PSIMD_MUL_S32, PSIMD_COMB_SUB)
+
+GEN_PSIMD_2WAY_MUL_ACC(pm2adda_h, target_ulong, int16_t, int16_t,
+ int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 2, 0, 1, 0, 1, PSIMD_MUL_S32,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2addasu_h, target_ulong, int16_t, uint16_t,
+ int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 2, 0, 1, 0, 1, PSIMD_MUL_SU32,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2addau_h, target_ulong, uint16_t, uint16_t,
+ uint32_t, uint32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 2, 0, 1, 0, 1, PSIMD_MUL_U32,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2adda_hx, target_ulong, int16_t, int16_t,
+ int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 2, 0, 1, 1, 0, PSIMD_MUL_S32,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2suba_h, target_ulong, int16_t, int16_t,
+ int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 2, 0, 1, 0, 1, PSIMD_MUL_S32,
+ PSIMD_COMB_SUB)
+GEN_PSIMD_2WAY_MUL_ACC(pm2suba_hx, target_ulong, int16_t, int16_t,
+ int32_t, int32_t, uint32_t, EXTRACT16, EXTRACT32,
+ INSERT32, ELEMS_W, 2, 0, 1, 1, 0, PSIMD_MUL_S32,
+ PSIMD_COMB_SUB)
+
+GEN_PSIMD_2WAY_MUL(pm2add_w, uint64_t, int32_t, int32_t,
+ int64_t, uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0,
+ 0, 1, 0, 1, PSIMD_MUL_S64, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2addsu_w, uint64_t, int32_t, uint32_t,
+ int64_t, uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0,
+ 0, 1, 0, 1, PSIMD_MUL_SU64, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2addu_w, uint64_t, uint32_t, uint32_t,
+ uint64_t, uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0,
+ 0, 1, 0, 1, PSIMD_MUL_U64, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2add_wx, uint64_t, int32_t, int32_t,
+ int64_t, uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0,
+ 0, 1, 1, 0, PSIMD_MUL_S64, PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL(pm2sub_w, uint64_t, int32_t, int32_t,
+ int64_t, uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0,
+ 0, 1, 0, 1, PSIMD_MUL_S64, PSIMD_COMB_SUB)
+GEN_PSIMD_2WAY_MUL(pm2sub_wx, uint64_t, int32_t, int32_t,
+ int64_t, uint64_t, EXTRACT32, INSERT64, ELEMS_D, 0,
+ 0, 1, 1, 0, PSIMD_MUL_S64, PSIMD_COMB_SUB)
+
+GEN_PSIMD_2WAY_MUL_ACC(pm2adda_w, uint64_t, int32_t, int32_t,
+ int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+ INSERT64, ELEMS_D, 0, 0, 1, 0, 1, PSIMD_MUL_S64,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2addasu_w, uint64_t, int32_t, uint32_t,
+ int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+ INSERT64, ELEMS_D, 0, 0, 1, 0, 1, PSIMD_MUL_SU64,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2addau_w, uint64_t, uint32_t, uint32_t,
+ uint64_t, uint64_t, uint64_t, EXTRACT32, EXTRACT64,
+ INSERT64, ELEMS_D, 0, 0, 1, 0, 1, PSIMD_MUL_U64,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2adda_wx, uint64_t, int32_t, int32_t,
+ int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+ INSERT64, ELEMS_D, 0, 0, 1, 1, 0, PSIMD_MUL_S64,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_2WAY_MUL_ACC(pm2suba_w, uint64_t, int32_t, int32_t,
+ int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+ INSERT64, ELEMS_D, 0, 0, 1, 0, 1, PSIMD_MUL_S64,
+ PSIMD_COMB_SUB)
+GEN_PSIMD_2WAY_MUL_ACC(pm2suba_wx, uint64_t, int32_t, int32_t,
+ int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
+ INSERT64, ELEMS_D, 0, 0, 1, 1, 0, PSIMD_MUL_S64,
+ PSIMD_COMB_SUB)
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 15/18] target/riscv: Add packed SIMD four-way MAC instructions
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (13 preceding siblings ...)
2026-07-17 10:07 ` [PATCH v2 14/18] target/riscv: Add packed SIMD two-way " Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
2026-07-17 10:07 ` [PATCH v2 16/18] target/riscv: Add packed SIMD load-replicate instructions Molly Chen
` (4 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/helper.h | 14 +++++++
target/riscv/insn32.decode | 14 +++++++
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 14 +++++++
target/riscv/tcg/psimd_helper.c | 41 +++++++++++++++++++++
4 files changed, 83 insertions(+)
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index b0743d19177..fb95a9f71b5 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1742,3 +1742,17 @@ DEF_HELPER_4(pm2addau_w, i64, env, i64, i64, i64)
DEF_HELPER_4(pm2adda_wx, i64, env, i64, i64, i64)
DEF_HELPER_4(pm2suba_w, i64, env, i64, i64, i64)
DEF_HELPER_4(pm2suba_wx, i64, env, i64, i64, i64)
+
+/* Packed SIMD - Four-Way Multiply and Accumulate Operations */
+DEF_HELPER_3(pm4add_b, tl, env, tl, tl)
+DEF_HELPER_3(pm4addsu_b, tl, env, tl, tl)
+DEF_HELPER_3(pm4addu_b, tl, env, tl, tl)
+DEF_HELPER_4(pm4adda_b, tl, env, tl, tl, tl)
+DEF_HELPER_4(pm4addasu_b, tl, env, tl, tl, tl)
+DEF_HELPER_4(pm4addau_b, tl, env, tl, tl, tl)
+DEF_HELPER_3(pm4add_h, i64, env, i64, i64)
+DEF_HELPER_3(pm4addsu_h, i64, env, i64, i64)
+DEF_HELPER_3(pm4addu_h, i64, env, i64, i64)
+DEF_HELPER_4(pm4adda_h, i64, env, i64, i64, i64)
+DEF_HELPER_4(pm4addasu_h, i64, env, i64, i64, i64)
+DEF_HELPER_4(pm4addau_h, i64, env, i64, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 1c8bdde25c2..8720fedb592 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -1600,3 +1600,17 @@ pm2addau_w 10101 01 ..... ..... 101 ..... 0111011 @r
pm2adda_wx 10011 01 ..... ..... 101 ..... 0111011 @r
pm2suba_w 11001 01 ..... ..... 101 ..... 0111011 @r
pm2suba_wx 11011 01 ..... ..... 101 ..... 0111011 @r
+
+# Packed SIMD - Four-Way Multiply and Accumulate Operations
+pm4add_b 10000 10 ..... ..... 101 ..... 0111011 @r
+pm4addsu_b 11100 10 ..... ..... 101 ..... 0111011 @r
+pm4addu_b 10100 10 ..... ..... 101 ..... 0111011 @r
+pm4adda_b 10001 10 ..... ..... 101 ..... 0111011 @r
+pm4addasu_b 11101 10 ..... ..... 101 ..... 0111011 @r
+pm4addau_b 10101 10 ..... ..... 101 ..... 0111011 @r
+pm4add_h 10000 11 ..... ..... 101 ..... 0111011 @r
+pm4addsu_h 11100 11 ..... ..... 101 ..... 0111011 @r
+pm4addu_h 10100 11 ..... ..... 101 ..... 0111011 @r
+pm4adda_h 10001 11 ..... ..... 101 ..... 0111011 @r
+pm4addasu_h 11101 11 ..... ..... 101 ..... 0111011 @r
+pm4addau_h 10101 11 ..... ..... 101 ..... 0111011 @r
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index cf670b144c3..6c344a66dc8 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -888,3 +888,17 @@ GEN_SIMD_TRANS_ACC_64(pm2adda_wx)
GEN_SIMD_TRANS_ACC_64(pm2suba_w)
GEN_SIMD_TRANS_ACC_64(pm2suba_wx)
+/* Packed SIMD - Four-Way Multiply and Accumulate Operations */
+GEN_SIMD_TRANS(pm4add_b)
+GEN_SIMD_TRANS(pm4addsu_b)
+GEN_SIMD_TRANS(pm4addu_b)
+GEN_SIMD_TRANS_ACC(pm4adda_b)
+GEN_SIMD_TRANS_ACC(pm4addasu_b)
+GEN_SIMD_TRANS_ACC(pm4addau_b)
+GEN_SIMD_TRANS_64(pm4add_h)
+GEN_SIMD_TRANS_64(pm4addsu_h)
+GEN_SIMD_TRANS_64(pm4addu_h)
+GEN_SIMD_TRANS_ACC_64(pm4adda_h)
+GEN_SIMD_TRANS_ACC_64(pm4addasu_h)
+GEN_SIMD_TRANS_ACC_64(pm4addau_h)
+
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index bad04937b54..e7c7e554938 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2849,3 +2849,44 @@ GEN_PSIMD_2WAY_MUL_ACC(pm2suba_wx, uint64_t, int32_t, int32_t,
int64_t, int64_t, uint64_t, EXTRACT32, EXTRACT64,
INSERT64, ELEMS_D, 0, 0, 1, 1, 0, PSIMD_MUL_S64,
PSIMD_COMB_SUB)
+
+
+/* Four-Way Multiply and Accumulate Operations */
+
+GEN_PSIMD_4WAY_MUL(pm4add_b, target_ulong, int8_t, int8_t,
+ int32_t, uint32_t, EXTRACT8, INSERT32, ELEMS_W, 4,
+ PSIMD_MUL_S32)
+GEN_PSIMD_4WAY_MUL(pm4addsu_b, target_ulong, int8_t, uint8_t,
+ int32_t, uint32_t, EXTRACT8, INSERT32, ELEMS_W, 4,
+ PSIMD_MUL_SU32)
+GEN_PSIMD_4WAY_MUL(pm4addu_b, target_ulong, uint8_t, uint8_t,
+ uint32_t, uint32_t, EXTRACT8, INSERT32, ELEMS_W, 4,
+ PSIMD_MUL_U32)
+GEN_PSIMD_4WAY_MUL_ACC(pm4adda_b, target_ulong, int8_t, int8_t,
+ int32_t, int32_t, uint32_t, EXTRACT8, EXTRACT32,
+ INSERT32, ELEMS_W, 4, PSIMD_MUL_S32)
+GEN_PSIMD_4WAY_MUL_ACC(pm4addasu_b, target_ulong, int8_t, uint8_t,
+ int32_t, int32_t, uint32_t, EXTRACT8, EXTRACT32,
+ INSERT32, ELEMS_W, 4, PSIMD_MUL_SU32)
+GEN_PSIMD_4WAY_MUL_ACC(pm4addau_b, target_ulong, uint8_t, uint8_t,
+ uint32_t, uint32_t, uint32_t, EXTRACT8, EXTRACT32,
+ INSERT32, ELEMS_W, 4, PSIMD_MUL_U32)
+
+GEN_PSIMD_4WAY_MUL(pm4add_h, uint64_t, int16_t, int16_t,
+ int64_t, uint64_t, EXTRACT16, INSERT64, ELEMS_D, 0,
+ PSIMD_MUL_S64)
+GEN_PSIMD_4WAY_MUL(pm4addsu_h, uint64_t, int16_t, uint16_t,
+ int64_t, uint64_t, EXTRACT16, INSERT64, ELEMS_D, 0,
+ PSIMD_MUL_SU64)
+GEN_PSIMD_4WAY_MUL(pm4addu_h, uint64_t, uint16_t, uint16_t,
+ uint64_t, uint64_t, EXTRACT16, INSERT64, ELEMS_D, 0,
+ PSIMD_MUL_U64)
+GEN_PSIMD_4WAY_MUL_ACC(pm4adda_h, uint64_t, int16_t, int16_t,
+ int64_t, int64_t, uint64_t, EXTRACT16, EXTRACT64,
+ INSERT64, ELEMS_D, 0, PSIMD_MUL_S64)
+GEN_PSIMD_4WAY_MUL_ACC(pm4addasu_h, uint64_t, int16_t, uint16_t,
+ int64_t, int64_t, uint64_t, EXTRACT16, EXTRACT64,
+ INSERT64, ELEMS_D, 0, PSIMD_MUL_SU64)
+GEN_PSIMD_4WAY_MUL_ACC(pm4addau_h, uint64_t, uint16_t, uint16_t,
+ uint64_t, uint64_t, uint64_t, EXTRACT16, EXTRACT64,
+ INSERT64, ELEMS_D, 0, PSIMD_MUL_U64)
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 16/18] target/riscv: Add packed SIMD load-replicate instructions
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (14 preceding siblings ...)
2026-07-17 10:07 ` [PATCH v2 15/18] target/riscv: Add packed SIMD four-way " Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
2026-07-17 10:07 ` [PATCH v2 17/18] target/riscv: Add packed SIMD RV32 only instructions Molly Chen
` (3 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/insn32.decode | 16 ++++++++++++++
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 24 +++++++++++++++++++++
target/riscv/tcg/translate.c | 2 ++
3 files changed, 42 insertions(+)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 8720fedb592..403e17e439d 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -44,6 +44,10 @@
%imm_p_ui16 20:4
%imm_p_ui32 20:5
%imm_p_ui64 20:6
+%imm_p_l1 16:8
+%imm_p_l2 15:s1 16:9
+%imm_p_l3 15:s9 24:1 !function=ex_shift_6
+%imm_p_l4 15:s9 24:1 !function=ex_shift_22
# Argument sets:
&empty
@@ -53,6 +57,7 @@
&r rd rs1 rs2
&r2 rd rs1
&r2_s rs1 rs2
+&p_l imm rd
&s imm rs1 rs2
&u imm rd
&shift shamt rs1 rd
@@ -114,6 +119,10 @@
@p_ui16 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui16 %rs1 %rd
@p_ui32 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui32 %rs1 %rd
@p_ui64 ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui64 %rs1 %rd
+@p_l1 ........ ........ .... ..... ....... &p_l imm=%imm_p_l1 %rd
+@p_l2 ....... .......... ... ..... ....... &p_l imm=%imm_p_l2 %rd
+@p_l3 ....... .......... ... ..... ....... &p_l imm=%imm_p_l3 %rd
+@p_l4 ....... .......... ... ..... ....... &p_l imm=%imm_p_l4 %rd
# Formats 64:
@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd
@@ -1614,3 +1623,10 @@ pm4addu_h 10100 11 ..... ..... 101 ..... 0111011 @r
pm4adda_h 10001 11 ..... ..... 101 ..... 0111011 @r
pm4addasu_h 11101 11 ..... ..... 101 ..... 0111011 @r
pm4addau_h 10101 11 ..... ..... 101 ..... 0111011 @r
+
+# Packed SIMD - Load and Replicate instructions
+pli_b 10110100 ........ 0010 ..... 0011011 @p_l1
+pli_h 1011000 .......... 010 ..... 0011011 @p_l2
+plui_h 1111000 .......... 010 ..... 0011011 @p_l3
+pli_w 1011001 ..... ..... 010 ..... 0011011 @p_l2
+plui_w 1111001 ..... ..... 010 ..... 0011011 @p_l4
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 6c344a66dc8..4d5fc230d2e 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -902,3 +902,27 @@ GEN_SIMD_TRANS_ACC_64(pm4adda_h)
GEN_SIMD_TRANS_ACC_64(pm4addasu_h)
GEN_SIMD_TRANS_ACC_64(pm4addau_h)
+#define GEN_PLI(NAME, PRE_REQ, IMM_TYPE, LIMIT, SHIFT, ADDEND) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ PRE_REQ \
+ REQUIRE_RVP(ctx); \
+ int i = 1; \
+ IMM_TYPE imm = a->imm; \
+ while (i < (LIMIT)) { \
+ imm = (imm << (SHIFT)) + (ADDEND); \
+ i++; \
+ } \
+ gen_set_gpri(ctx, a->rd, imm); \
+ return true; \
+}
+
+GEN_PLI(pli_b, , target_long, TARGET_LONG_SIZE, 8, a->imm)
+GEN_PLI(pli_h, , target_long, TARGET_LONG_SIZE / 2, 16,
+ a->imm & 0xFFFF)
+GEN_PLI(plui_h, , target_long, TARGET_LONG_SIZE / 2, 16,
+ a->imm & 0xFFFF)
+GEN_PLI(pli_w, REQUIRE_64BIT(ctx); , int64_t, TARGET_LONG_SIZE / 4, 32,
+ a->imm & 0xFFFFFFFF)
+GEN_PLI(plui_w, REQUIRE_64BIT(ctx); , int64_t, TARGET_LONG_SIZE / 4, 32,
+ a->imm & 0xFFFFFFFF)
diff --git a/target/riscv/tcg/translate.c b/target/riscv/tcg/translate.c
index 0df9d4190f1..668ec3120af 100644
--- a/target/riscv/tcg/translate.c
+++ b/target/riscv/tcg/translate.c
@@ -790,7 +790,9 @@ EX_SH(1)
EX_SH(2)
EX_SH(3)
EX_SH(4)
+EX_SH(6)
EX_SH(12)
+EX_SH(22)
#define REQUIRE_EXT(ctx, ext) do { \
if (!has_ext(ctx, ext)) { \
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 17/18] target/riscv: Add packed SIMD RV32 only instructions
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (15 preceding siblings ...)
2026-07-17 10:07 ` [PATCH v2 16/18] target/riscv: Add packed SIMD load-replicate instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
2026-07-17 10:07 ` [PATCH v2 18/18] target/riscv: Remove Zbkb dependency from P extension to align with the spec Molly Chen
` (2 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/helper.h | 131 ++++++
target/riscv/insn32.decode | 285 +++++++++++-
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 461 ++++++++++++++++++++
target/riscv/tcg/psimd_helper.c | 273 ++++++++++++
4 files changed, 1149 insertions(+), 1 deletion(-)
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index fb95a9f71b5..78e6f17be82 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -1756,3 +1756,134 @@ DEF_HELPER_3(pm4addu_h, i64, env, i64, i64)
DEF_HELPER_4(pm4adda_h, i64, env, i64, i64, i64)
DEF_HELPER_4(pm4addasu_h, i64, env, i64, i64, i64)
DEF_HELPER_4(pm4addau_h, i64, env, i64, i64, i64)
+
+/* Packed SIMD - Double-Width Operations (RV32 only, register pairs) */
+DEF_HELPER_3(pwadd_b, i64, env, i32, i32)
+DEF_HELPER_4(pwadda_b, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwaddu_b, i64, env, i32, i32)
+DEF_HELPER_4(pwaddau_b, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwsub_b, i64, env, i32, i32)
+DEF_HELPER_4(pwsuba_b, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwsubu_b, i64, env, i32, i32)
+DEF_HELPER_4(pwsubau_b, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwslli_b, i64, env, i32, i32)
+DEF_HELPER_3(pwsll_bs, i64, env, i32, i32)
+DEF_HELPER_3(pwslai_b, i64, env, i32, i32)
+DEF_HELPER_3(pwsla_bs, i64, env, i32, i32)
+
+DEF_HELPER_3(pwadd_h, i64, env, i32, i32)
+DEF_HELPER_4(pwadda_h, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwaddu_h, i64, env, i32, i32)
+DEF_HELPER_4(pwaddau_h, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwsub_h, i64, env, i32, i32)
+DEF_HELPER_4(pwsuba_h, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwsubu_h, i64, env, i32, i32)
+DEF_HELPER_4(pwsubau_h, i64, env, i32, i32, i64)
+DEF_HELPER_3(pwslli_h, i64, env, i32, i32)
+DEF_HELPER_3(pwsll_hs, i64, env, i32, i32)
+DEF_HELPER_3(pwslai_h, i64, env, i32, i32)
+DEF_HELPER_3(pwsla_hs, i64, env, i32, i32)
+
+DEF_HELPER_3(wadd, i64, env, i32, i32)
+DEF_HELPER_4(wadda, i64, env, i32, i32, i64)
+DEF_HELPER_3(waddu, i64, env, i32, i32)
+DEF_HELPER_4(waddau, i64, env, i32, i32, i64)
+DEF_HELPER_3(wsub, i64, env, i32, i32)
+DEF_HELPER_4(wsuba, i64, env, i32, i32, i64)
+DEF_HELPER_3(wsubu, i64, env, i32, i32)
+DEF_HELPER_4(wsubau, i64, env, i32, i32, i64)
+DEF_HELPER_3(wslli, i64, env, i32, i32)
+DEF_HELPER_3(wsll, i64, env, i32, i32)
+DEF_HELPER_3(wslai, i64, env, i32, i32)
+DEF_HELPER_3(wsla, i64, env, i32, i32)
+
+DEF_HELPER_3(wzip8p, i64, env, i32, i32)
+DEF_HELPER_3(wzip16p, i64, env, i32, i32)
+
+DEF_HELPER_4(predsum_dbs, i32, env, i32, i32, i32)
+DEF_HELPER_4(predsumu_dbs, i32, env, i32, i32, i32)
+DEF_HELPER_4(predsum_dhs, i32, env, i32, i32, i32)
+DEF_HELPER_4(predsumu_dhs, i32, env, i32, i32, i32)
+
+DEF_HELPER_3(pnsrli_b, i32, env, i64, i32)
+DEF_HELPER_3(pnsrai_b, i32, env, i64, i32)
+DEF_HELPER_3(pnsrari_b, i32, env, i64, i32)
+DEF_HELPER_3(pnclipi_b, i32, env, i64, i32)
+DEF_HELPER_3(pnclipri_b, i32, env, i64, i32)
+DEF_HELPER_3(pnclipiu_b, i32, env, i64, i32)
+DEF_HELPER_3(pnclipriu_b, i32, env, i64, i32)
+DEF_HELPER_3(pnsrl_bs, i32, env, i64, i32)
+DEF_HELPER_3(pnsra_bs, i32, env, i64, i32)
+DEF_HELPER_3(pnsrar_bs, i32, env, i64, i32)
+DEF_HELPER_3(pnclip_bs, i32, env, i64, i32)
+DEF_HELPER_3(pnclipr_bs, i32, env, i64, i32)
+DEF_HELPER_3(pnclipu_bs, i32, env, i64, i32)
+DEF_HELPER_3(pnclipru_bs, i32, env, i64, i32)
+
+DEF_HELPER_3(pnsrli_h, i32, env, i64, i32)
+DEF_HELPER_3(pnsrai_h, i32, env, i64, i32)
+DEF_HELPER_3(pnsrari_h, i32, env, i64, i32)
+DEF_HELPER_3(pnclipi_h, i32, env, i64, i32)
+DEF_HELPER_3(pnclipri_h, i32, env, i64, i32)
+DEF_HELPER_3(pnclipiu_h, i32, env, i64, i32)
+DEF_HELPER_3(pnclipriu_h, i32, env, i64, i32)
+DEF_HELPER_3(pnsrl_hs, i32, env, i64, i32)
+DEF_HELPER_3(pnsra_hs, i32, env, i64, i32)
+DEF_HELPER_3(pnsrar_hs, i32, env, i64, i32)
+DEF_HELPER_3(pnclip_hs, i32, env, i64, i32)
+DEF_HELPER_3(pnclipr_hs, i32, env, i64, i32)
+DEF_HELPER_3(pnclipu_hs, i32, env, i64, i32)
+DEF_HELPER_3(pnclipru_hs, i32, env, i64, i32)
+
+DEF_HELPER_3(nsrli, i32, env, i64, i32)
+DEF_HELPER_3(nsrai, i32, env, i64, i32)
+DEF_HELPER_3(nsrari, i32, env, i64, i32)
+DEF_HELPER_3(nclipi, i32, env, i64, i32)
+DEF_HELPER_3(nclipri, i32, env, i64, i32)
+DEF_HELPER_3(nclipiu, i32, env, i64, i32)
+DEF_HELPER_3(nclipriu, i32, env, i64, i32)
+DEF_HELPER_3(nsrl, i32, env, i64, i32)
+DEF_HELPER_3(nsra, i32, env, i64, i32)
+DEF_HELPER_3(nsrar, i32, env, i64, i32)
+DEF_HELPER_3(nclip, i32, env, i64, i32)
+DEF_HELPER_3(nclipr, i32, env, i64, i32)
+DEF_HELPER_3(nclipu, i32, env, i64, i32)
+DEF_HELPER_3(nclipru, i32, env, i64, i32)
+
+DEF_HELPER_4(pmqwacc_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(pmqrwacc_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(mqwacc, i64, env, i32, i32, i64)
+DEF_HELPER_4(mqrwacc, i64, env, i32, i32, i64)
+
+DEF_HELPER_3(pwmul_b, i64, env, i32, i32)
+DEF_HELPER_3(pwmulsu_b, i64, env, i32, i32)
+DEF_HELPER_3(pwmulu_b, i64, env, i32, i32)
+DEF_HELPER_3(pwmul_h, i64, env, i32, i32)
+DEF_HELPER_3(pwmulsu_h, i64, env, i32, i32)
+DEF_HELPER_3(pwmulu_h, i64, env, i32, i32)
+
+DEF_HELPER_4(pwmacc_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(pwmaccsu_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(pwmaccu_h, i64, env, i32, i32, i64)
+
+DEF_HELPER_3(wmul, i64, env, i32, i32)
+DEF_HELPER_3(wmulsu, i64, env, i32, i32)
+DEF_HELPER_3(wmulu, i64, env, i32, i32)
+
+DEF_HELPER_4(wmacc, i64, env, i32, i32, i64)
+DEF_HELPER_4(wmaccsu, i64, env, i32, i32, i64)
+DEF_HELPER_4(wmaccu, i64, env, i32, i32, i64)
+
+DEF_HELPER_3(pm2wadd_h, i64, env, i32, i32)
+DEF_HELPER_3(pm2waddsu_h, i64, env, i32, i32)
+DEF_HELPER_3(pm2waddu_h, i64, env, i32, i32)
+DEF_HELPER_3(pm2wadd_hx, i64, env, i32, i32)
+DEF_HELPER_4(pm2wadda_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(pm2waddasu_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(pm2waddau_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(pm2wadda_hx, i64, env, i32, i32, i64)
+
+DEF_HELPER_3(pm2wsub_h, i64, env, i32, i32)
+DEF_HELPER_3(pm2wsub_hx, i64, env, i32, i32)
+DEF_HELPER_4(pm2wsuba_h, i64, env, i32, i32, i64)
+DEF_HELPER_4(pm2wsuba_hx, i64, env, i32, i32, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 403e17e439d..a477b812fd6 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -23,6 +23,9 @@
%rd 7:5
%sh5 20:5
%sh6 20:6
+%rs2_p 21:4
+%rs1_p 16:4
+%rd_p 8:4
%sh7 20:7
%csr 20:12
@@ -57,7 +60,6 @@
&r rd rs1 rs2
&r2 rd rs1
&r2_s rs1 rs2
-&p_l imm rd
&s imm rs1 rs2
&u imm rd
&shift shamt rs1 rd
@@ -69,6 +71,7 @@
&k_aes shamt rs2 rs1 rd
&mop5 imm rd rs1
&mop3 imm rd rs1 rs2
+&p_l imm rd
&p_ui imm rs1 rd
# Formats 32:
@@ -102,6 +105,11 @@
@r2_zimm11 . zimm:11 ..... ... ..... ....... %rs1 %rd
@r2_zimm10 .. zimm:10 ..... ... ..... ....... %rs1 %rd
@r2_s ....... ..... ..... ... ..... ....... %rs2 %rs1
+@r_p_1 ....... ..... ..... ... ..... ....... &r %rs2 %rs1 rd=%rd_p
+@r_p_2 ....... ..... ..... ... ..... ....... &r rs2=%rs2_p rs1=%rs1_p rd=%rd_p
+@r_p_3 ....... ..... ..... ... ..... ....... &r %rs2 rs1=%rs1_p rd=%rd_p
+@r_p_4 ....... ..... ..... ... ..... ....... &r %rs2 rs1=%rs1_p %rd
+@r2_p ....... ..... ..... ... ..... ....... &r2 rs1=%rs1_p rd=%rd_p
@hfence_gvma ....... ..... ..... ... ..... ....... %rs2 %rs1
@hfence_vvma ....... ..... ..... ... ..... ....... %rs2 %rs1
@@ -123,6 +131,18 @@
@p_l2 ....... .......... ... ..... ....... &p_l imm=%imm_p_l2 %rd
@p_l3 ....... .......... ... ..... ....... &p_l imm=%imm_p_l3 %rd
@p_l4 ....... .......... ... ..... ....... &p_l imm=%imm_p_l4 %rd
+@p_l1_p ........ ........ .... ..... ....... &p_l imm=%imm_p_l1 rd=%rd_p
+@p_l2_p ........ ........ .... ..... ....... &p_l imm=%imm_p_l2 rd=%rd_p
+@p_l3_p ....... .......... ... ..... ....... &p_l imm=%imm_p_l3 rd=%rd_p
+@p_ui8_p ..... .... ... ..... ... ..... ....... &i imm=%imm_p_ui8 rs1=%rs1_p rd=%rd_p
+@p_ui16_p ..... .... ... ..... ... ..... ....... &p_ui imm=%imm_p_ui16 %rs1 rd=%rd_p
+@p_ui16_p_2 ..... .... ... ..... ... ..... ....... &p_ui imm=%imm_p_ui16 rs1=%rs1_p rd=%rd_p
+@p_ui16_p_3 ..... .... ... .... .... ..... ....... &p_ui imm=%imm_p_ui16 rs1=%rs1_p %rd
+@p_ui32_p ..... .... ... ..... ... ..... ....... &p_ui imm=%imm_p_ui32 %rs1 rd=%rd_p
+@p_ui32_p_2 ..... .... ... ..... ... ..... ....... &p_ui imm=%imm_p_ui32 rs1=%rs1_p rd=%rd_p
+@p_ui32_p_3 ..... .... ... ..... ... ..... ....... &p_ui imm=%imm_p_ui32 rs1=%rs1_p %rd
+@p_ui64_p ..... .... ... ..... ... ..... ....... &p_ui imm=%imm_p_ui64 %rs1 rd=%rd_p
+@p_ui64_p_2 ..... .... ... ..... ... ..... ....... &p_ui imm=%imm_p_ui64 rs1=%rs1_p %rd
# Formats 64:
@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd
@@ -1630,3 +1650,266 @@ pli_h 1011000 .......... 010 ..... 0011011 @p_l2
plui_h 1111000 .......... 010 ..... 0011011 @p_l3
pli_w 1011001 ..... ..... 010 ..... 0011011 @p_l2
plui_w 1111001 ..... ..... 010 ..... 0011011 @p_l4
+
+# Packed SIMD - Double-Width Operations (RV32 only, register pairs)
+# register-pair destination
+pwadd_b 0000010 ..... ..... 010 .... 10011011 @r_p_1
+pwadda_b 0000110 ..... ..... 010 .... 10011011 @r_p_1
+pwaddu_b 0001010 ..... ..... 010 .... 10011011 @r_p_1
+pwaddau_b 0001110 ..... ..... 010 .... 10011011 @r_p_1
+pwsub_b 0100010 ..... ..... 010 .... 10011011 @r_p_1
+pwsuba_b 0100110 ..... ..... 010 .... 10011011 @r_p_1
+pwsubu_b 0101010 ..... ..... 010 .... 10011011 @r_p_1
+pwsubau_b 0101110 ..... ..... 010 .... 10011011 @r_p_1
+pwslli_b 00000 001.... ..... 010 .... 00011011 @p_ui16_p
+pwsll_bs 0000100 ..... ..... 010 .... 00011011 @r_p_1
+pwslai_b 01000 001.... ..... 010 .... 00011011 @p_ui16_p
+pwsla_bs 0100100 ..... ..... 010 .... 00011011 @r_p_1
+
+pwadd_h 0000000 ..... ..... 010 .... 10011011 @r_p_1
+pwadda_h 0000100 ..... ..... 010 .... 10011011 @r_p_1
+pwaddu_h 0001000 ..... ..... 010 .... 10011011 @r_p_1
+pwaddau_h 0001100 ..... ..... 010 .... 10011011 @r_p_1
+pwsub_h 0100000 ..... ..... 010 .... 10011011 @r_p_1
+pwsuba_h 0100100 ..... ..... 010 .... 10011011 @r_p_1
+pwsubu_h 0101000 ..... ..... 010 .... 10011011 @r_p_1
+pwsubau_h 0101100 ..... ..... 010 .... 10011011 @r_p_1
+pwslli_h 00000 01..... ..... 010 .... 00011011 @p_ui32_p
+pwsll_hs 0000101 ..... ..... 010 .... 00011011 @r_p_1
+pwslai_h 01000 01..... ..... 010 .... 00011011 @p_ui32_p
+pwsla_hs 0100101 ..... ..... 010 .... 00011011 @r_p_1
+
+wadd 0000001 ..... ..... 010 .... 10011011 @r_p_1
+wadda 0000101 ..... ..... 010 .... 10011011 @r_p_1
+waddu 0001001 ..... ..... 010 .... 10011011 @r_p_1
+waddau 0001101 ..... ..... 010 .... 10011011 @r_p_1
+wsub 0100001 ..... ..... 010 .... 10011011 @r_p_1
+wsuba 0100101 ..... ..... 010 .... 10011011 @r_p_1
+wsubu 0101001 ..... ..... 010 .... 10011011 @r_p_1
+wsubau 0101101 ..... ..... 010 .... 10011011 @r_p_1
+wslli 00000 1...... ..... 010 .... 00011011 @p_ui64_p
+wsll 0000111 ..... ..... 010 .... 00011011 @r_p_1
+wslai 01000 1...... ..... 010 .... 00011011 @p_ui64_p
+wsla 0100111 ..... ..... 010 .... 00011011 @r_p_1
+
+wzip8p 0111100 ..... ..... 010 .... 00011011 @r_p_1
+wzip16p 0111101 ..... ..... 010 .... 00011011 @r_p_1
+
+#register-pair operands
+pli_db 00110100 ........ 0010 .... 00011011 @p_l1_p
+padd_db 1000010 .... 0 .... 0110 .... 00011011 @r_p_2
+psub_db 1100010 .... 0 .... 0110 .... 00011011 @r_p_2
+psadd_db 1001010 .... 0 .... 0110 .... 00011011 @r_p_2
+psaddu_db 1011010 .... 0 .... 0110 .... 00011011 @r_p_2
+pssub_db 1101010 .... 0 .... 0110 .... 00011011 @r_p_2
+pssubu_db 1111010 .... 0 .... 0110 .... 00011011 @r_p_2
+paadd_db 1001110 .... 0 .... 0110 .... 00011011 @r_p_2
+paaddu_db 1011110 .... 0 .... 0110 .... 00011011 @r_p_2
+pasub_db 1101110 .... 0 .... 0110 .... 00011011 @r_p_2
+pasubu_db 1111110 .... 0 .... 0110 .... 00011011 @r_p_2
+pabd_db 1100110 .... 0 .... 0110 .... 00011011 @r_p_2
+pabdu_db 1110110 .... 0 .... 0110 .... 00011011 @r_p_2
+psabs_db 0110010 00111 .... 0110 .... 00011011 @r2_p
+pli_dh 0011000 .......... 010 .... 00011011 @p_l2_p
+plui_dh 0111000 .......... 010 .... 00011011 @p_l3_p
+padd_dh 1000000 .... 0 .... 0110 .... 00011011 @r_p_2
+psub_dh 1100000 .... 0 .... 0110 .... 00011011 @r_p_2
+psadd_dh 1001000 .... 0 .... 0110 .... 00011011 @r_p_2
+psaddu_dh 1011000 .... 0 .... 0110 .... 00011011 @r_p_2
+pssub_dh 1101000 .... 0 .... 0110 .... 00011011 @r_p_2
+pssubu_dh 1111000 .... 0 .... 0110 .... 00011011 @r_p_2
+paadd_dh 1001100 .... 0 .... 0110 .... 00011011 @r_p_2
+paaddu_dh 1011100 .... 0 .... 0110 .... 00011011 @r_p_2
+pasub_dh 1101100 .... 0 .... 0110 .... 00011011 @r_p_2
+pasubu_dh 1111100 .... 0 .... 0110 .... 00011011 @r_p_2
+psh1add_dh 1010000 .... 1 .... 0110 .... 00011011 @r_p_2
+pssh1sadd_dh 1011000 .... 1 .... 0110 .... 00011011 @r_p_2
+pas_dhx 1000000 .... 1 .... 1110 .... 00011011 @r_p_2
+psa_dhx 1000010 .... 1 .... 1110 .... 00011011 @r_p_2
+psas_dhx 1001000 .... 1 .... 1110 .... 00011011 @r_p_2
+pssa_dhx 1001010 .... 1 .... 1110 .... 00011011 @r_p_2
+paas_dhx 1001100 .... 1 .... 1110 .... 00011011 @r_p_2
+pasa_dhx 1001110 .... 1 .... 1110 .... 00011011 @r_p_2
+pabd_dh 1100100 .... 0 .... 0110 .... 00011011 @r_p_2
+pabdu_dh 1110100 .... 0 .... 0110 .... 00011011 @r_p_2
+psabs_dh 0110000 00111 .... 0110 .... 00011011 @r2_p
+padd_dw 1000001 .... 0 .... 0110 .... 00011011 @r_p_2
+psub_dw 1100001 .... 0 .... 0110 .... 00011011 @r_p_2
+psadd_dw 1001001 .... 0 .... 0110 .... 00011011 @r_p_2
+psaddu_dw 1011001 .... 0 .... 0110 .... 00011011 @r_p_2
+pssub_dw 1101001 .... 0 .... 0110 .... 00011011 @r_p_2
+pssubu_dw 1111001 .... 0 .... 0110 .... 00011011 @r_p_2
+paadd_dw 1001101 .... 0 .... 0110 .... 00011011 @r_p_2
+paaddu_dw 1011101 .... 0 .... 0110 .... 00011011 @r_p_2
+pasub_dw 1101101 .... 0 .... 0110 .... 00011011 @r_p_2
+pasubu_dw 1111101 .... 0 .... 0110 .... 00011011 @r_p_2
+psh1add_dw 1010001 .... 1 .... 0110 .... 00011011 @r_p_2
+pssh1sadd_dw 1011001 .... 1 .... 0110 .... 00011011 @r_p_2
+addd_p 1000011 .... 0 .... 0110 .... 00011011 @r_p_2
+subd_p 1100011 .... 0 .... 0110 .... 00011011 @r_p_2
+
+# register-pair first source only
+predsum_dbs 0001110 ..... .... 0100 ..... 0011011 @r_p_4
+predsumu_dbs 0011110 ..... .... 0100 ..... 0011011 @r_p_4
+predsum_dhs 0001100 ..... .... 0100 ..... 0011011 @r_p_4
+predsumu_dhs 0011100 ..... .... 0100 ..... 0011011 @r_p_4
+
+# register-pair operands
+pslli_db 00000 0001... .... 0110 .... 00011011 @p_ui8_p
+psrli_db 00000 0001... .... 1110 .... 00011011 @p_ui8_p
+psrai_db 01000 0001... .... 1110 .... 00011011 @p_ui8_p
+pmin_db 1110010 .... 1 .... 1110 .... 00011011 @r_p_2
+pminu_db 1110110 .... 1 .... 1110 .... 00011011 @r_p_2
+pmax_db 1111010 .... 1 .... 1110 .... 00011011 @r_p_2
+pmaxu_db 1111110 .... 1 .... 1110 .... 00011011 @r_p_2
+pmseq_db 1100010 .... 1 .... 1110 .... 00011011 @r_p_2
+pmslt_db 1101010 .... 1 .... 1110 .... 00011011 @r_p_2
+pmsltu_db 1101110 .... 1 .... 1110 .... 00011011 @r_p_2
+psext_dh_b 0110000 00100 .... 0110 .... 00011011 @r2_p
+psati_dh 01100 001.... .... 1110 .... 00011011 @p_ui16_p_2
+pusati_dh 00100 001.... .... 1110 .... 00011011 @p_ui16_p_2
+pslli_dh 00000 001.... .... 0110 .... 00011011 @p_ui16_p_2
+psrli_dh 00000 001.... .... 1110 .... 00011011 @p_ui16_p_2
+psrai_dh 01000 001.... .... 1110 .... 00011011 @p_ui16_p_2
+psslai_dh 01010 001.... .... 0110 .... 00011011 @p_ui16_p_2
+psrari_dh 01010 001.... .... 1110 .... 00011011 @p_ui16_p_2
+pmin_dh 1110000 .... 1 .... 1110 .... 00011011 @r_p_2
+pminu_dh 1110100 .... 1 .... 1110 .... 00011011 @r_p_2
+pmax_dh 1111000 .... 1 .... 1110 .... 00011011 @r_p_2
+pmaxu_dh 1111100 .... 1 .... 1110 .... 00011011 @r_p_2
+pmseq_dh 1100000 .... 1 .... 1110 .... 00011011 @r_p_2
+pmslt_dh 1101000 .... 1 .... 1110 .... 00011011 @r_p_2
+pmsltu_dh 1101100 .... 1 .... 1110 .... 00011011 @r_p_2
+psext_dw_b 0110001 00100 .... 0110 .... 00011011 @r2_p
+psext_dw_h 0110001 00101 .... 0110 .... 00011011 @r2_p
+psati_dw 01100 01..... .... 1110 .... 00011011 @p_ui32_p_2
+pusati_dw 00100 01..... .... 1110 .... 00011011 @p_ui32_p_2
+pslli_dw 00000 01..... .... 0110 .... 00011011 @p_ui32_p_2
+psrli_dw 00000 01..... .... 1110 .... 00011011 @p_ui32_p_2
+psrai_dw 01000 01..... .... 1110 .... 00011011 @p_ui32_p_2
+psslai_dw 01010 01..... .... 0110 .... 00011011 @p_ui32_p_2
+psrari_dw 01010 01..... .... 1110 .... 00011011 @p_ui32_p_2
+pmin_dw 1110001 .... 1 .... 1110 .... 00011011 @r_p_2
+pminu_dw 1110101 .... 1 .... 1110 .... 00011011 @r_p_2
+pmax_dw 1111001 .... 1 .... 1110 .... 00011011 @r_p_2
+pmaxu_dw 1111101 .... 1 .... 1110 .... 00011011 @r_p_2
+pmseq_dw 1100001 .... 1 .... 1110 .... 00011011 @r_p_2
+pmslt_dw 1101001 .... 1 .... 1110 .... 00011011 @r_p_2
+pmsltu_dw 1101101 .... 1 .... 1110 .... 00011011 @r_p_2
+
+# register-pair first source and dest
+padd_dbs 0001110 ..... .... 0110 .... 00011011 @r_p_3
+psll_dbs 0000110 ..... .... 0110 .... 00011011 @r_p_3
+psrl_dbs 0000110 ..... .... 1110 .... 00011011 @r_p_3
+psra_dbs 0100110 ..... .... 1110 .... 00011011 @r_p_3
+padd_dhs 0001100 ..... .... 0110 .... 00011011 @r_p_3
+psll_dhs 0000100 ..... .... 0110 .... 00011011 @r_p_3
+psrl_dhs 0000100 ..... .... 1110 .... 00011011 @r_p_3
+psra_dhs 0100100 ..... .... 1110 .... 00011011 @r_p_3
+pssha_dhs 0110100 ..... .... 0110 .... 00011011 @r_p_3
+psshar_dhs 0111100 ..... .... 0110 .... 00011011 @r_p_3
+psshl_dhs 0010100 ..... .... 0110 .... 00011011 @r_p_3
+psshlr_dhs 0011100 ..... .... 0110 .... 00011011 @r_p_3
+padd_dws 0001101 ..... .... 0110 .... 00011011 @r_p_3
+psll_dws 0000101 ..... .... 0110 .... 00011011 @r_p_3
+psrl_dws 0000101 ..... .... 1110 .... 00011011 @r_p_3
+psra_dws 0100101 ..... .... 1110 .... 00011011 @r_p_3
+pssha_dws 0110101 ..... .... 0110 .... 00011011 @r_p_3
+psshar_dws 0111101 ..... .... 0110 .... 00011011 @r_p_3
+psshl_dws 0010101 ..... .... 0110 .... 00011011 @r_p_3
+psshlr_dws 0011101 ..... .... 0110 .... 00011011 @r_p_3
+
+# register-pair operands
+ppaire_db 1000000 .... 0 .... 1110 .... 00011011 @r_p_2
+ppaireo_db 1001000 .... 0 .... 1110 .... 00011011 @r_p_2
+ppairoe_db 1010000 .... 0 .... 1110 .... 00011011 @r_p_2
+ppairo_db 1011000 .... 0 .... 1110 .... 00011011 @r_p_2
+ppaire_dh 1000001 .... 0 .... 1110 .... 00011011 @r_p_2
+ppaireo_dh 1001001 .... 0 .... 1110 .... 00011011 @r_p_2
+ppairoe_dh 1010001 .... 0 .... 1110 .... 00011011 @r_p_2
+ppairo_dh 1011001 .... 0 .... 1110 .... 00011011 @r_p_2
+
+#register-pair first source only
+pnsrli_b 00000 001.... .... 1100 ..... 0011011 @p_ui16_p_3
+pnsrai_b 01000 001.... .... 1100 ..... 0011011 @p_ui16_p_3
+pnsrari_b 01010 001.... .... 1100 ..... 0011011 @p_ui16_p_3
+pnclipi_b 01100 001.... .... 1100 ..... 0011011 @p_ui16_p_3
+pnclipri_b 01110 001.... .... 1100 ..... 0011011 @p_ui16_p_3
+pnclipiu_b 00100 001.... .... 1100 ..... 0011011 @p_ui16_p_3
+pnclipriu_b 00110 001.... .... 1100 ..... 0011011 @p_ui16_p_3
+pnsrl_bs 00001 00 ..... .... 1100 ..... 0011011 @r_p_4
+pnsra_bs 01001 00 ..... .... 1100 ..... 0011011 @r_p_4
+pnsrar_bs 01011 00 ..... .... 1100 ..... 0011011 @r_p_4
+pnclip_bs 01101 00 ..... .... 1100 ..... 0011011 @r_p_4
+pnclipr_bs 01111 00 ..... .... 1100 ..... 0011011 @r_p_4
+pnclipu_bs 00101 00 ..... .... 1100 ..... 0011011 @r_p_4
+pnclipru_bs 00111 00 ..... .... 1100 ..... 0011011 @r_p_4
+
+pnsrli_h 00000 01..... .... 1100 ..... 0011011 @p_ui32_p_3
+pnsrai_h 01000 01..... .... 1100 ..... 0011011 @p_ui32_p_3
+pnsrari_h 01010 01..... .... 1100 ..... 0011011 @p_ui32_p_3
+pnclipi_h 01100 01..... .... 1100 ..... 0011011 @p_ui32_p_3
+pnclipri_h 01110 01..... .... 1100 ..... 0011011 @p_ui32_p_3
+pnclipiu_h 00100 01..... .... 1100 ..... 0011011 @p_ui32_p_3
+pnclipriu_h 00110 01..... .... 1100 ..... 0011011 @p_ui32_p_3
+pnsrl_hs 00001 01 ..... .... 1100 ..... 0011011 @r_p_4
+pnsra_hs 01001 01 ..... .... 1100 ..... 0011011 @r_p_4
+pnsrar_hs 01011 01 ..... .... 1100 ..... 0011011 @r_p_4
+pnclip_hs 01101 01 ..... .... 1100 ..... 0011011 @r_p_4
+pnclipr_hs 01111 01 ..... .... 1100 ..... 0011011 @r_p_4
+pnclipu_hs 00101 01 ..... .... 1100 ..... 0011011 @r_p_4
+pnclipru_hs 00111 01 ..... .... 1100 ..... 0011011 @r_p_4
+
+nsrli 00000 1...... .... 1100 ..... 0011011 @p_ui64_p_2
+nsrai 01000 1...... .... 1100 ..... 0011011 @p_ui64_p_2
+nsrari 01010 1...... .... 1100 ..... 0011011 @p_ui64_p_2
+nclipi 01100 1...... .... 1100 ..... 0011011 @p_ui64_p_2
+nclipri 01110 1...... .... 1100 ..... 0011011 @p_ui64_p_2
+nclipiu 00100 1...... .... 1100 ..... 0011011 @p_ui64_p_2
+nclipriu 00110 1...... .... 1100 ..... 0011011 @p_ui64_p_2
+nsrl 00001 11 ..... .... 1100 ..... 0011011 @r_p_4
+nsra 01001 11 ..... .... 1100 ..... 0011011 @r_p_4
+nsrar 01011 11 ..... .... 1100 ..... 0011011 @r_p_4
+nclip 01101 11 ..... .... 1100 ..... 0011011 @r_p_4
+nclipr 01111 11 ..... .... 1100 ..... 0011011 @r_p_4
+nclipu 00101 11 ..... .... 1100 ..... 0011011 @r_p_4
+nclipru 00111 11 ..... .... 1100 ..... 0011011 @r_p_4
+
+# register-pair multiply
+pmqwacc_h 01111 00 ..... ..... 010 .... 10011011 @r_p_1
+pmqrwacc_h 01111 10 ..... ..... 010 .... 10011011 @r_p_1
+mqwacc 01111 01 ..... ..... 010 .... 10011011 @r_p_1
+mqrwacc 01111 11 ..... ..... 010 .... 10011011 @r_p_1
+
+pwmul_b 00100 10 ..... ..... 010 .... 10011011 @r_p_1
+pwmulsu_b 01100 10 ..... ..... 010 .... 10011011 @r_p_1
+pwmulu_b 00110 10 ..... ..... 010 .... 10011011 @r_p_1
+
+pwmul_h 00100 00 ..... ..... 010 .... 10011011 @r_p_1
+pwmulsu_h 01100 00 ..... ..... 010 .... 10011011 @r_p_1
+pwmulu_h 00110 00 ..... ..... 010 .... 10011011 @r_p_1
+pwmacc_h 00101 00 ..... ..... 010 .... 10011011 @r_p_1
+pwmaccsu_h 01101 00 ..... ..... 010 .... 10011011 @r_p_1
+pwmaccu_h 00111 00 ..... ..... 010 .... 10011011 @r_p_1
+
+wmul 00100 01 ..... ..... 010 .... 10011011 @r_p_1
+wmulsu 01100 01 ..... ..... 010 .... 10011011 @r_p_1
+wmulu 00110 01 ..... ..... 010 .... 10011011 @r_p_1
+wmacc 00101 01 ..... ..... 010 .... 10011011 @r_p_1
+wmaccsu 01101 01 ..... ..... 010 .... 10011011 @r_p_1
+wmaccu 00111 01 ..... ..... 010 .... 10011011 @r_p_1
+
+pm2wadd_h 00000 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2waddsu_h 01100 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2waddu_h 00100 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2wadd_hx 00010 11 ..... ..... 010 .... 10011011 @r_p_1
+
+pm2wadda_h 00001 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2waddasu_h 01101 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2waddau_h 00101 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2wadda_hx 00011 11 ..... ..... 010 .... 10011011 @r_p_1
+
+pm2wsub_h 01000 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2wsub_hx 01010 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2wsuba_h 01001 11 ..... ..... 010 .... 10011011 @r_p_1
+pm2wsuba_hx 01011 11 ..... ..... 010 .... 10011011 @r_p_1
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index 4d5fc230d2e..e33e0ec110a 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -3,6 +3,36 @@
/* Copyright (c) 2026 ISRC ISCAS. */
/* Save a 64 bit data in src to dst and dst + 1 */
+static void set_pair_regs(DisasContext *ctx, int dst, TCGv_i64 src)
+{
+#if defined(TARGET_RISCV32)
+ TCGv_i64 tl_64 = tcg_temp_new_i64();
+ TCGv_i64 th_64 = tcg_temp_new_i64();
+ TCGv_i32 tl_32 = tcg_temp_new_i32();
+ TCGv_i32 th_32 = tcg_temp_new_i32();
+ tcg_gen_extract_i64(tl_64, src, 0, 32);
+ tcg_gen_extract_i64(th_64, src, 32, 32);
+ tcg_gen_trunc_i64_tl(tl_32, tl_64);
+ tcg_gen_trunc_i64_tl(th_32, th_64);
+ gen_set_gpr(ctx, dst, tl_32);
+ gen_set_gpr(ctx, dst + 1, th_32);
+# else
+ gen_set_gpr(ctx, dst, src);
+#endif
+}
+
+/* Concat two 32 bit data in src and src + 1 to dst */
+static void get_pair_regs(DisasContext *ctx, TCGv_i64 dst, int src)
+{
+#if defined(TARGET_RISCV32)
+ TCGv t1 = get_gpr(ctx, src, EXT_NONE);
+ TCGv t2 = get_gpr(ctx, src + 1, EXT_NONE);
+ tcg_gen_concat_i32_i64(dst, t1, t2);
+#else
+ TCGv t1 = get_gpr(ctx, src, EXT_NONE);
+ tcg_gen_mov_tl(dst, t1);
+#endif
+}
static bool require_rvp(DisasContext *ctx)
{
@@ -902,6 +932,241 @@ GEN_SIMD_TRANS_ACC_64(pm4adda_h)
GEN_SIMD_TRANS_ACC_64(pm4addasu_h)
GEN_SIMD_TRANS_ACC_64(pm4addau_h)
+/* Packed SIMD - Double-Width Operations (RV32 only, register pairs) */
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwadd_b)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwadda_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwaddu_b)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwaddau_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsub_b)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwsuba_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsubu_b)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwsubau_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(pwslli_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsll_bs)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(pwslai_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsla_bs)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwadd_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwadda_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwaddu_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwaddau_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsub_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwsuba_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsubu_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwsubau_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(pwslli_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsll_hs)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(pwslai_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwsla_hs)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wadd)
+GEN_SIMD_TRANS_REG_PAIR_ACC(wadda)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(waddu)
+GEN_SIMD_TRANS_REG_PAIR_ACC(waddau)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wsub)
+GEN_SIMD_TRANS_REG_PAIR_ACC(wsuba)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wsubu)
+GEN_SIMD_TRANS_REG_PAIR_ACC(wsubau)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(wslli)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wsll)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR_IMM(wslai)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wsla)
+
+GEN_SIMD_TRANS_REG_PAIR_LANE(padd_db, padd_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(psub_db, psub_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(psadd_db, psadd_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(psaddu_db, psaddu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssub_db, pssub_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssubu_db, pssubu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(paadd_db, paadd_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(paaddu_db, paaddu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pasub_db, pasub_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pasubu_db, pasubu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pabd_db, pabd_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pabdu_db, pabdu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(psabs_db, psabs_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(padd_dh, padd_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(psub_dh, psub_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(psadd_dh, psadd_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(psaddu_dh, psaddu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssub_dh, pssub_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssubu_dh, pssubu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(paadd_dh, paadd_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(paaddu_dh, paaddu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pasub_dh, pasub_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pasubu_dh, pasubu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(psh1add_dh, psh1add_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssh1sadd_dh, pssh1sadd_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pas_dhx, pas_hx)
+GEN_SIMD_TRANS_REG_PAIR_LANE(psa_dhx, psa_hx)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(psas_dhx, psas_hx)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssa_dhx, pssa_hx)
+GEN_SIMD_TRANS_REG_PAIR_LANE(paas_dhx, paas_hx)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pasa_dhx, pasa_hx)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pabd_dh, pabd_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pabdu_dh, pabdu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY_VXSAT(psabs_dh, psabs_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(psadd_dw, sadd)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(psaddu_dw, saddu)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssub_dw, ssub)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssubu_dw, ssubu)
+GEN_SIMD_TRANS_REG_PAIR_LANE(paadd_dw, aadd)
+GEN_SIMD_TRANS_REG_PAIR_LANE(paaddu_dw, aaddu)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pasub_dw, asub)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pasubu_dw, asubu)
+GEN_SIMD_TRANS_REG_PAIR_LANE_VXSAT(pssh1sadd_dw, ssh1sadd)
+
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(pslli_db, pslli_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(psrli_db, psrli_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(psrai_db, psrai_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmin_db, pmin_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pminu_db, pminu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmax_db, pmax_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmaxu_db, pmaxu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmseq_db, pmseq_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmslt_db, pmslt_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmsltu_db, pmsltu_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_UNARY(psext_dh_b, psext_h_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(psati_dh, psati_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(pusati_dh, pusati_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(pslli_dh, pslli_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(psrli_dh, psrli_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(psrai_dh, psrai_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(psslai_dh, psslai_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(psrari_dh, psrari_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmin_dh, pmin_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pminu_dh, pminu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmax_dh, pmax_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmaxu_dh, pmaxu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmseq_dh, pmseq_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmslt_dh, pmslt_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmsltu_dh, pmsltu_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(psati_dw, sati_32)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(pusati_dw, usati_32)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM_VXSAT(psslai_dw, sslai)
+GEN_SIMD_TRANS_REG_PAIR_LANE_IMM(psrari_dw, srari_32)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmseq_dw, mseq)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmslt_dw, mslt)
+GEN_SIMD_TRANS_REG_PAIR_LANE(pmsltu_dw, msltu)
+
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(padd_dbs, padd_bs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(psll_dbs, psll_bs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(psrl_dbs, psrl_bs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(psra_dbs, psra_bs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(padd_dhs, padd_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(psll_dhs, psll_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(psrl_dhs, psrl_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR(psra_dhs, psra_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(pssha_dhs, pssha_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(psshar_dhs, psshar_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(psshl_dhs, psshl_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(psshlr_dhs, psshlr_hs)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(pssha_dws, ssha)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(psshar_dws, sshar)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(psshl_dws, sshl)
+GEN_SIMD_TRANS_REG_PAIR_LANE_SCALAR_VXSAT(psshlr_dws, sshlr)
+
+GEN_SIMD_TRANS_REG_PAIR_LANE(ppairo_db, ppairo_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(ppairo_dh, ppairo_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(ppaire_db, ppaire_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(ppaireo_db, ppaireo_b)
+GEN_SIMD_TRANS_REG_PAIR_LANE(ppaireo_dh, ppaireo_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(ppairoe_dh, ppairoe_h)
+GEN_SIMD_TRANS_REG_PAIR_LANE(ppairoe_db, ppairoe_b)
+
+GEN_SIMD_TRANS_REG_PAIR_PREDSUM(predsum_dbs)
+GEN_SIMD_TRANS_REG_PAIR_PREDSUM(predsumu_dbs)
+GEN_SIMD_TRANS_REG_PAIR_PREDSUM(predsum_dhs)
+GEN_SIMD_TRANS_REG_PAIR_PREDSUM(predsumu_dhs)
+
+GEN_SIMD_TRANS_PN_OP_IMM(pnsrli_b)
+GEN_SIMD_TRANS_PN_OP_IMM(pnsrai_b)
+GEN_SIMD_TRANS_PN_OP_IMM(pnsrari_b)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipi_b)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipri_b)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipiu_b)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipriu_b)
+
+GEN_SIMD_TRANS_PN_OP_IMM(pnsrli_h)
+GEN_SIMD_TRANS_PN_OP_IMM(pnsrai_h)
+GEN_SIMD_TRANS_PN_OP_IMM(pnsrari_h)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipi_h)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipri_h)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipiu_h)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(pnclipriu_h)
+
+GEN_SIMD_TRANS_PN_OP_IMM(nsrli)
+GEN_SIMD_TRANS_PN_OP_IMM(nsrai)
+GEN_SIMD_TRANS_PN_OP_IMM(nsrari)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(nclipi)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(nclipri)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(nclipiu)
+GEN_SIMD_TRANS_PN_OP_IMM_VXSAT(nclipriu)
+
+GEN_SIMD_TRANS_PN_OP_REG(pnsrl_bs)
+GEN_SIMD_TRANS_PN_OP_REG(pnsra_bs)
+GEN_SIMD_TRANS_PN_OP_REG(pnsrar_bs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclip_bs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclipr_bs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclipu_bs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclipru_bs)
+
+GEN_SIMD_TRANS_PN_OP_REG(pnsrl_hs)
+GEN_SIMD_TRANS_PN_OP_REG(pnsra_hs)
+GEN_SIMD_TRANS_PN_OP_REG(pnsrar_hs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclip_hs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclipr_hs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclipu_hs)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(pnclipru_hs)
+
+GEN_SIMD_TRANS_PN_OP_REG(nsrl)
+GEN_SIMD_TRANS_PN_OP_REG(nsra)
+GEN_SIMD_TRANS_PN_OP_REG(nsrar)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(nclip)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(nclipr)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(nclipu)
+GEN_SIMD_TRANS_PN_OP_REG_VXSAT(nclipru)
+
+GEN_SIMD_TRANS_REG_PAIR_ACC(pmqwacc_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pmqrwacc_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(mqwacc)
+GEN_SIMD_TRANS_REG_PAIR_ACC(mqrwacc)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwmul_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwmulsu_b)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwmulu_b)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwmul_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwmulsu_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pwmulu_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwmacc_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwmaccsu_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pwmaccu_h)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wmul)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wmulsu)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(wmulu)
+
+GEN_SIMD_TRANS_REG_PAIR_ACC(wmacc)
+GEN_SIMD_TRANS_REG_PAIR_ACC(wmaccsu)
+GEN_SIMD_TRANS_REG_PAIR_ACC(wmaccu)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pm2wadd_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pm2waddsu_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pm2waddu_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pm2wadd_hx)
+
+GEN_SIMD_TRANS_REG_PAIR_ACC(pm2wadda_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pm2waddasu_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pm2waddau_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pm2wadda_hx)
+
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pm2wsub_h)
+GEN_SIMD_TRANS_REG_PAIR_SCALAR(pm2wsub_hx)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pm2wsuba_h)
+GEN_SIMD_TRANS_REG_PAIR_ACC(pm2wsuba_hx)
+
#define GEN_PLI(NAME, PRE_REQ, IMM_TYPE, LIMIT, SHIFT, ADDEND) \
static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
{ \
@@ -917,6 +1182,21 @@ static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
return true; \
}
+#define GEN_PLI_D(NAME, IMM_TYPE, LIMIT, SHIFT, ADDEND) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_RVP(ctx); \
+ int i = 1; \
+ IMM_TYPE imm = a->imm; \
+ while (i < (LIMIT)) { \
+ imm = (imm << (SHIFT)) + (ADDEND); \
+ i++; \
+ } \
+ gen_set_gpri(ctx, (a->rd) * 2, imm); \
+ gen_set_gpri(ctx, (a->rd) * 2 + 1, imm); \
+ return true; \
+}
+
GEN_PLI(pli_b, , target_long, TARGET_LONG_SIZE, 8, a->imm)
GEN_PLI(pli_h, , target_long, TARGET_LONG_SIZE / 2, 16,
a->imm & 0xFFFF)
@@ -926,3 +1206,184 @@ GEN_PLI(pli_w, REQUIRE_64BIT(ctx); , int64_t, TARGET_LONG_SIZE / 4, 32,
a->imm & 0xFFFFFFFF)
GEN_PLI(plui_w, REQUIRE_64BIT(ctx); , int64_t, TARGET_LONG_SIZE / 4, 32,
a->imm & 0xFFFFFFFF)
+GEN_PLI_D(pli_db, target_long, TARGET_LONG_SIZE, 8, a->imm)
+GEN_PLI_D(pli_dh, target_long, TARGET_LONG_SIZE / 2, 16,
+ a->imm & 0xFFFF)
+GEN_PLI_D(plui_dh, target_long, TARGET_LONG_SIZE / 2, 16,
+ a->imm & 0xFFFF)
+
+#define GEN_DW_LANE_BINOP(NAME, OP) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ REQUIRE_RVP(ctx); \
+ TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
+ TCGv src2_0 = get_gpr(ctx, (a->rs2) * 2, EXT_NONE); \
+ TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2); \
+ TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
+ TCGv src2_1 = get_gpr(ctx, (a->rs2) * 2 + 1, EXT_NONE); \
+ TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1); \
+ OP(dest_0, src1_0, src2_0); \
+ OP(dest_1, src1_1, src2_1); \
+ gen_set_gpr(ctx, (a->rd) * 2, dest_0); \
+ gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1); \
+ return true; \
+}
+
+GEN_DW_LANE_BINOP(padd_dw, tcg_gen_add_tl)
+GEN_DW_LANE_BINOP(psub_dw, tcg_gen_sub_tl)
+GEN_DW_LANE_BINOP(psh1add_dw, gen_sh1add)
+
+/* Verify rd is not zero register for wzip8p and wzip16p. */
+#if defined(TARGET_RISCV32)
+#define GEN_WZIP_P(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ REQUIRE_RVP(ctx); \
+ TCGv_i32 src1 = get_gpr(ctx, a->rs1, EXT_NONE); \
+ TCGv_i32 src2 = get_gpr(ctx, a->rs2, EXT_NONE); \
+ TCGv_i64 t = tcg_temp_new_i64(); \
+ if (a->rd == 0) { \
+ return true; \
+ } else { \
+ get_pair_regs(ctx, t, (a->rd) * 2); \
+ } \
+ gen_helper_##NAME(t, tcg_env, src1, src2); \
+ set_pair_regs(ctx, (a->rd) * 2, t); \
+ return true; \
+}
+#else
+#define GEN_WZIP_P(NAME) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ return true; \
+}
+#endif
+
+GEN_WZIP_P(wzip8p)
+GEN_WZIP_P(wzip16p)
+
+#define GEN_PAIR_I64_BINOP(NAME, OP) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ REQUIRE_RVP(ctx); \
+ TCGv_i64 src1 = tcg_temp_new_i64(); \
+ TCGv_i64 src2 = tcg_temp_new_i64(); \
+ TCGv_i64 dest = tcg_temp_new_i64(); \
+ get_pair_regs(ctx, src1, (a->rs1) * 2); \
+ get_pair_regs(ctx, src2, (a->rs2) * 2); \
+ get_pair_regs(ctx, dest, (a->rd) * 2); \
+ OP(dest, src1, src2); \
+ set_pair_regs(ctx, (a->rd) * 2, dest); \
+ return true; \
+}
+
+GEN_PAIR_I64_BINOP(addd_p, tcg_gen_add_i64)
+GEN_PAIR_I64_BINOP(subd_p, tcg_gen_sub_i64)
+
+#define GEN_DW_EXT(NAME, OP) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ REQUIRE_RVP(ctx); \
+ TCGv dest_0 = dest_gpr(ctx, (a->rd) * 2); \
+ TCGv src1_0 = get_gpr(ctx, (a->rs1) * 2, EXT_NONE); \
+ TCGv dest_1 = dest_gpr(ctx, (a->rd) * 2 + 1); \
+ TCGv src1_1 = get_gpr(ctx, (a->rs1) * 2 + 1, EXT_NONE); \
+ OP(dest_0, src1_0); \
+ gen_set_gpr(ctx, (a->rd) * 2, dest_0); \
+ OP(dest_1, src1_1); \
+ gen_set_gpr(ctx, (a->rd) * 2 + 1, dest_1); \
+ return true; \
+}
+
+GEN_DW_EXT(psext_dw_b, tcg_gen_ext8s_tl)
+GEN_DW_EXT(psext_dw_h, tcg_gen_ext16s_tl)
+
+#define GEN_DW_SHIFT_IMM(NAME, OP) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ REQUIRE_RVP(ctx); \
+ arg_shift a0, a1; \
+ a0.rd = (a->rd) * 2; \
+ a0.rs1 = (a->rs1) * 2; \
+ a0.shamt = a->imm; \
+ a1.rd = (a->rd) * 2 + 1; \
+ a1.rs1 = (a->rs1) * 2 + 1; \
+ a1.shamt = a->imm; \
+ gen_shift_imm_fn(ctx, &a0, EXT_NONE, OP, NULL); \
+ gen_shift_imm_fn(ctx, &a1, EXT_NONE, OP, NULL); \
+ return true; \
+}
+
+#define GEN_DW_SHIFT_IMM_PER_OL(NAME, OP, OP_OL) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ REQUIRE_RVP(ctx); \
+ arg_shift a0, a1; \
+ a0.rd = (a->rd) * 2; \
+ a0.rs1 = (a->rs1) * 2; \
+ a0.shamt = a->imm; \
+ a1.rd = (a->rd) * 2 + 1; \
+ a1.rs1 = (a->rs1) * 2 + 1; \
+ a1.shamt = a->imm; \
+ gen_shift_imm_fn_per_ol(ctx, &a0, EXT_NONE, OP, OP_OL, NULL); \
+ gen_shift_imm_fn_per_ol(ctx, &a1, EXT_NONE, OP, OP_OL, NULL); \
+ return true; \
+}
+
+GEN_DW_SHIFT_IMM(pslli_dw, tcg_gen_shli_tl)
+GEN_DW_SHIFT_IMM_PER_OL(psrli_dw, tcg_gen_shri_tl, gen_srliw)
+GEN_DW_SHIFT_IMM_PER_OL(psrai_dw, tcg_gen_sari_tl, gen_sraiw)
+
+#define GEN_DW_PAIR_ARITH(NAME, EXTRA_REQ, EXT, OP) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ REQUIRE_RVP(ctx); \
+ EXTRA_REQ \
+ arg_r a0, a1; \
+ a0.rd = (a->rd) * 2; \
+ a0.rs1 = (a->rs1) * 2; \
+ a0.rs2 = (a->rs2) * 2; \
+ a1.rd = (a->rd) * 2 + 1; \
+ a1.rs1 = (a->rs1) * 2 + 1; \
+ a1.rs2 = (a->rs2) * 2 + 1; \
+ gen_arith(ctx, &a0, EXT, OP, NULL); \
+ gen_arith(ctx, &a1, EXT, OP, NULL); \
+ return true; \
+}
+
+GEN_DW_PAIR_ARITH(pmin_dw, REQUIRE_ZBB(ctx); , EXT_SIGN, tcg_gen_smin_tl)
+GEN_DW_PAIR_ARITH(pminu_dw, REQUIRE_ZBB(ctx); , EXT_SIGN, tcg_gen_umin_tl)
+GEN_DW_PAIR_ARITH(pmax_dw, REQUIRE_ZBB(ctx); , EXT_SIGN, tcg_gen_smax_tl)
+GEN_DW_PAIR_ARITH(pmaxu_dw, REQUIRE_ZBB(ctx); , EXT_SIGN, tcg_gen_umax_tl)
+
+#define GEN_DWS_REG_OP(NAME, GEN, EXT, OP) \
+static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \
+{ \
+ REQUIRE_32BIT(ctx); \
+ REQUIRE_RVP(ctx); \
+ arg_r a0, a1; \
+ a0.rd = (a->rd) * 2; \
+ a0.rs1 = (a->rs1) * 2; \
+ a0.rs2 = a->rs2; \
+ a1.rd = (a->rd) * 2 + 1; \
+ a1.rs1 = (a->rs1) * 2 + 1; \
+ a1.rs2 = a->rs2; \
+ GEN(ctx, &a0, EXT, OP, NULL); \
+ GEN(ctx, &a1, EXT, OP, NULL); \
+ return true; \
+}
+
+GEN_DWS_REG_OP(padd_dws, gen_arith, EXT_NONE, tcg_gen_add_tl)
+GEN_DWS_REG_OP(psll_dws, gen_shift, EXT_NONE, tcg_gen_shl_tl)
+GEN_DWS_REG_OP(psrl_dws, gen_shift, EXT_ZERO, tcg_gen_shr_tl)
+GEN_DWS_REG_OP(psra_dws, gen_shift, EXT_SIGN, tcg_gen_sar_tl)
+
+GEN_DW_PAIR_ARITH(ppaire_dh, REQUIRE_ZBKB(ctx); , EXT_NONE, gen_pack)
diff --git a/target/riscv/tcg/psimd_helper.c b/target/riscv/tcg/psimd_helper.c
index e7c7e554938..c69adae10cc 100644
--- a/target/riscv/tcg/psimd_helper.c
+++ b/target/riscv/tcg/psimd_helper.c
@@ -2890,3 +2890,276 @@ GEN_PSIMD_4WAY_MUL_ACC(pm4addasu_h, uint64_t, int16_t, uint16_t,
GEN_PSIMD_4WAY_MUL_ACC(pm4addau_h, uint64_t, uint16_t, uint16_t,
uint64_t, uint64_t, uint64_t, EXTRACT16, EXTRACT64,
INSERT64, ELEMS_D, 0, PSIMD_MUL_U64)
+
+/* Double-Width Operations (RV32 only, register pairs) */
+
+GEN_PSIMD_WIDEN_BINOP(pwadd_b, int8_t, int16_t, uint16_t,
+ 4, 8, 16, 0xFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwadda_b, int8_t, int16_t, uint16_t,
+ 4, 8, 16, 0xFF, 0xFFFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP(pwaddu_b, uint8_t, uint16_t, uint16_t,
+ 4, 8, 16, 0xFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwaddau_b, uint8_t, uint16_t, uint16_t,
+ 4, 8, 16, 0xFF, 0xFFFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP(pwsub_b, int8_t, int16_t, uint16_t,
+ 4, 8, 16, 0xFF, PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwsuba_b, int8_t, int16_t, uint16_t,
+ 4, 8, 16, 0xFF, 0xFFFF, PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP(pwsubu_b, uint8_t, uint16_t, uint16_t,
+ 4, 8, 16, 0xFF, PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwsubau_b, uint8_t, uint16_t, uint16_t,
+ 4, 8, 16, 0xFF, 0xFFFF, PSIMD_COMB_SUB)
+
+GEN_PSIMD_WIDEN_SHIFT(pwslli_b, uint8_t, uint16_t, uint16_t,
+ 4, 8, 16, 0xFF, 0x0F)
+GEN_PSIMD_WIDEN_SHIFT(pwsll_bs, uint8_t, uint16_t, uint16_t,
+ 4, 8, 16, 0xFF, 0x1F)
+GEN_PSIMD_WIDEN_SHIFT(pwslai_b, int8_t, int16_t, uint16_t,
+ 4, 8, 16, 0xFF, 0x0F)
+GEN_PSIMD_WIDEN_SHIFT(pwsla_bs, int8_t, int16_t, uint16_t,
+ 4, 8, 16, 0xFF, 0x1F)
+
+GEN_PSIMD_WIDEN_BINOP(pwadd_h, int16_t, int32_t, uint32_t,
+ 2, 16, 32, 0xFFFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwadda_h, int16_t, int32_t, uint32_t,
+ 2, 16, 32, 0xFFFF, 0xFFFFFFFFULL,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP(pwaddu_h, uint16_t, uint32_t, uint32_t,
+ 2, 16, 32, 0xFFFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwaddau_h, uint16_t, uint32_t, uint32_t,
+ 2, 16, 32, 0xFFFF, 0xFFFFFFFFULL,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP(pwsub_h, int16_t, int32_t, uint32_t,
+ 2, 16, 32, 0xFFFF, PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwsuba_h, int16_t, int32_t, uint32_t,
+ 2, 16, 32, 0xFFFF, 0xFFFFFFFFULL,
+ PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP(pwsubu_h, uint16_t, uint32_t, uint32_t,
+ 2, 16, 32, 0xFFFF, PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP_ACC(pwsubau_h, uint16_t, uint32_t, uint32_t,
+ 2, 16, 32, 0xFFFF, 0xFFFFFFFFULL,
+ PSIMD_COMB_SUB)
+
+GEN_PSIMD_WIDEN_SHIFT(pwslli_h, uint16_t, uint32_t, uint32_t,
+ 2, 16, 32, 0xFFFF, 0x1F)
+GEN_PSIMD_WIDEN_SHIFT(pwsll_hs, uint16_t, uint32_t, uint32_t,
+ 2, 16, 32, 0xFFFF, 0x1F)
+GEN_PSIMD_WIDEN_SHIFT(pwslai_h, int16_t, int32_t, uint32_t,
+ 2, 16, 32, 0xFFFF, 0x1F)
+GEN_PSIMD_WIDEN_SHIFT(pwsla_hs, int16_t, int32_t, uint32_t,
+ 2, 16, 32, 0xFFFF, 0x1F)
+
+GEN_PSIMD_WIDEN_BINOP(wadd, int32_t, int64_t, uint64_t,
+ 1, 32, 64, 0xFFFFFFFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP_ACC(wadda, int32_t, int64_t, uint64_t,
+ 1, 32, 64, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFFULL,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP(waddu, uint32_t, uint64_t, uint64_t,
+ 1, 32, 64, 0xFFFFFFFF, PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP_ACC(waddau, uint32_t, uint64_t, uint64_t,
+ 1, 32, 64, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFFULL,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_WIDEN_BINOP(wsub, int32_t, int64_t, uint64_t,
+ 1, 32, 64, 0xFFFFFFFF, PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP_ACC(wsuba, int32_t, int64_t, uint64_t,
+ 1, 32, 64, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFFULL,
+ PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP(wsubu, uint32_t, uint64_t, uint64_t,
+ 1, 32, 64, 0xFFFFFFFF, PSIMD_COMB_SUB)
+GEN_PSIMD_WIDEN_BINOP_ACC(wsubau, uint32_t, uint64_t, uint64_t,
+ 1, 32, 64, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFFULL,
+ PSIMD_COMB_SUB)
+
+GEN_PSIMD_WIDEN_SHIFT(wslli, uint32_t, uint64_t, uint64_t,
+ 1, 32, 64, 0xFFFFFFFF, 0x3F)
+GEN_PSIMD_WIDEN_SHIFT(wsll, uint32_t, uint64_t, uint64_t,
+ 1, 32, 64, 0xFFFFFFFF, 0x3F)
+GEN_PSIMD_WIDEN_SHIFT(wslai, int32_t, int64_t, uint64_t,
+ 1, 32, 64, 0xFFFFFFFF, 0x3F)
+GEN_PSIMD_WIDEN_SHIFT(wsla, int32_t, int64_t, uint64_t,
+ 1, 32, 64, 0xFFFFFFFF, 0x3F)
+
+GEN_PSIMD_DW_ZIP(wzip8p, EXTRACT8, 4, 16, 8)
+GEN_PSIMD_DW_ZIP(wzip16p, EXTRACT16, 2, 32, 16)
+
+GEN_PSIMD_DW_REDSUM(predsum_dbs, int64_t, int32_t, int8_t, EXTRACT8, 8)
+GEN_PSIMD_DW_REDSUM(predsumu_dbs, uint64_t, uint32_t, uint8_t, EXTRACT8, 8)
+GEN_PSIMD_DW_REDSUM(predsum_dhs, int64_t, int32_t, int16_t, EXTRACT16, 4)
+GEN_PSIMD_DW_REDSUM(predsumu_dhs, uint64_t, uint32_t, uint16_t, EXTRACT16, 4)
+
+
+/* Narrowing Operations (RV32 only, register pair sources) */
+
+GEN_PSIMD_NARROW_SRL(pnsrli_b, uint16_t, uint8_t,
+ 4, 16, 8, 0xFFFF, 0x0F)
+GEN_PSIMD_NARROW_SRL(pnsrl_bs, uint16_t, uint8_t,
+ 4, 16, 8, 0xFFFF, 0x1F)
+GEN_PSIMD_NARROW_SRA_PACK(pnsrai_b, int16_t, int32_t, uint8_t,
+ 4, 16, 8, 0xFFFF, 0x0F)
+GEN_PSIMD_NARROW_SRA_PACK(pnsra_bs, int16_t, int32_t, uint8_t,
+ 4, 16, 8, 0xFFFF, 0x1F)
+GEN_PSIMD_NARROW_RNDSRA_PACK(pnsrari_b, int16_t, int32_t, uint8_t,
+ 4, 16, 8, 0xFFFF, 0x0F, 0x1FF)
+GEN_PSIMD_NARROW_RNDSRA_PACK(pnsrar_bs, int16_t, int32_t, uint8_t,
+ 4, 16, 8, 0xFFFF, 0x1F, 0x1FF)
+GEN_PSIMD_NCLIP_SIGNED_PACK(pnclipi_b, int16_t, int32_t, int16_t,
+ uint8_t, 4, 16, 8, 0xFFFF, 0x0F,
+ -128, 127, 0x80, 0x7F)
+GEN_PSIMD_NCLIPR_SIGNED_PACK(pnclipri_b, int16_t, int32_t, int16_t,
+ uint8_t, 4, 16, 8, 0xFFFF, 0x0F, 0x1FFFF,
+ -128, 127, 0x80, 0x7F)
+GEN_PSIMD_NCLIP_UNSIGNED_PACK(pnclipiu_b, uint16_t, uint16_t, uint8_t,
+ 4, 16, 8, 0xFFFF, 0x0F, 0x00FF)
+GEN_PSIMD_NCLIPR_UNSIGNED_PACK(pnclipriu_b, uint16_t, uint32_t, uint8_t,
+ 4, 16, 8, 0xFFFF, 0x0F, 0x00FF)
+GEN_PSIMD_NCLIP_SIGNED_PACK(pnclip_bs, int16_t, int32_t, int16_t,
+ uint8_t, 4, 16, 8, 0xFFFF, 0x1F,
+ -128, 127, 0x80, 0x7F)
+GEN_PSIMD_NCLIPR_SIGNED_PACK(pnclipr_bs, int16_t, int32_t, int16_t,
+ uint8_t, 4, 16, 8, 0xFFFF, 0x1F, 0x1FFFF,
+ -128, 127, 0x80, 0x7F)
+GEN_PSIMD_NCLIP_UNSIGNED_PACK(pnclipu_bs, uint16_t, uint32_t, uint8_t,
+ 4, 16, 8, 0xFFFF, 0x1F, 0x00FF)
+GEN_PSIMD_NCLIPR_UNSIGNED_PACK(pnclipru_bs, uint16_t, uint64_t, uint8_t,
+ 4, 16, 8, 0xFFFF, 0x1F, 0x00FF)
+
+GEN_PSIMD_NARROW_SRL(pnsrli_h, uint32_t, uint16_t,
+ 2, 32, 16, 0xFFFFFFFFULL, 0x1F)
+GEN_PSIMD_NARROW_SRA_PACK(pnsrai_h, int32_t, int64_t, uint16_t,
+ 2, 32, 16, 0xFFFFFFFFULL, 0x1F)
+GEN_PSIMD_NARROW_RNDSRA_PACK(pnsrari_h, int32_t, int64_t, uint16_t,
+ 2, 32, 16, 0xFFFFFFFFULL, 0x1F, 0x1FFFF)
+
+GEN_PSIMD_NARROW_SRL(pnsrl_hs, uint32_t, uint16_t,
+ 2, 32, 16, 0xFFFFFFFFULL, 0x1F)
+
+GEN_PSIMD_NARROW_ALIAS(pnsra_hs, pnsrai_h)
+GEN_PSIMD_NARROW_ALIAS(pnsrar_hs, pnsrari_h)
+
+GEN_PSIMD_NCLIP_SIGNED_PACK(pnclip_hs, int32_t, int64_t, int32_t,
+ uint16_t, 2, 32, 16, 0xFFFFFFFFULL, 0x1F,
+ -32768, 32767, 0x8000, 0x7FFF)
+GEN_PSIMD_NCLIPR_SIGNED_PACK(pnclipr_hs, int32_t, int64_t, int32_t,
+ uint16_t, 2, 32, 16, 0xFFFFFFFFULL, 0x1F,
+ 0x1FFFFFFFF, -32768, 32767, 0x8000, 0x7FFF)
+
+GEN_PSIMD_NARROW_ALIAS(pnclipi_h, pnclip_hs)
+GEN_PSIMD_NARROW_ALIAS(pnclipri_h, pnclipr_hs)
+
+GEN_PSIMD_NCLIP_UNSIGNED_PACK(pnclipu_hs, uint32_t, uint32_t, uint16_t,
+ 2, 32, 16, 0xFFFFFFFFULL, 0x1F, 0xFFFF)
+GEN_PSIMD_NCLIPR_UNSIGNED_PACK(pnclipru_hs, uint32_t, uint64_t, uint16_t,
+ 2, 32, 16, 0xFFFFFFFFULL, 0x1F, 0xFFFF)
+
+GEN_PSIMD_NARROW_ALIAS(pnclipiu_h, pnclipu_hs)
+GEN_PSIMD_NARROW_ALIAS(pnclipriu_h, pnclipru_hs)
+
+GEN_PSIMD_NARROW_SRL(nsrli, uint64_t, uint32_t,
+ 1, 64, 32, 0xFFFFFFFFFFFFFFFFULL, 0x3F)
+
+GEN_PSIMD_NARROW_SRA(nsrai)
+GEN_PSIMD_NARROW_RNDSRA(nsrari)
+
+GEN_PSIMD_NARROW_SRL(nsrl, uint64_t, uint32_t,
+ 1, 64, 32, 0xFFFFFFFFFFFFFFFFULL, 0x3F)
+
+GEN_PSIMD_NARROW_SRA(nsra)
+GEN_PSIMD_NARROW_RNDSRA(nsrar)
+
+GEN_PSIMD_NCLIP(nclipi)
+GEN_PSIMD_NCLIPR(nclipri)
+GEN_PSIMD_NCLIPU(nclipiu)
+GEN_PSIMD_NCLIPRU(nclipriu)
+
+GEN_PSIMD_NCLIP(nclip)
+GEN_PSIMD_NCLIPR(nclipr)
+GEN_PSIMD_NCLIPU(nclipu)
+GEN_PSIMD_NCLIPRU(nclipru)
+
+/* Multiplication with Even-Odd Register Pairs as Destination (RV32 only) */
+
+GEN_PSIMD_WIDEN_QMUL_ACC(pmqwacc_h, int16_t, int32_t, int64_t,
+ int32_t, uint32_t, 2, EXTRACT16, EXTRACT32,
+ 2, 0, 15, 0, 32, PSIMD_MUL_S64)
+GEN_PSIMD_WIDEN_QMUL_ACC(pmqrwacc_h, int16_t, int32_t, int64_t,
+ int32_t, uint32_t, 2, EXTRACT16, EXTRACT32,
+ 2, 0, 15, 1LL << 14, 32, PSIMD_MUL_S64)
+
+GEN_PSIMD_WIDEN_MUL(pwmul_b, int8_t, int8_t, int16_t, uint16_t,
+ 4, EXTRACT8, 16, PSIMD_MUL_S32)
+GEN_PSIMD_WIDEN_MUL(pwmulsu_b, int8_t, uint8_t, int16_t, uint16_t,
+ 4, EXTRACT8, 16, PSIMD_MUL_SU16)
+GEN_PSIMD_WIDEN_MUL(pwmulu_b, uint8_t, uint8_t, uint16_t, uint16_t,
+ 4, EXTRACT8, 16, PSIMD_MUL_U32)
+GEN_PSIMD_WIDEN_MUL(pwmul_h, int16_t, int16_t, int32_t, uint32_t,
+ 2, EXTRACT16, 32, PSIMD_MUL_S32)
+GEN_PSIMD_WIDEN_MUL(pwmulsu_h, int16_t, uint16_t, int32_t, uint32_t,
+ 2, EXTRACT16, 32, PSIMD_MUL_SU32)
+GEN_PSIMD_WIDEN_MUL(pwmulu_h, uint16_t, uint16_t, uint32_t, uint32_t,
+ 2, EXTRACT16, 32, PSIMD_MUL_U32)
+
+GEN_PSIMD_WIDEN_MUL_ACC(pwmacc_h, int16_t, int16_t, int32_t,
+ int32_t, uint32_t, 2, EXTRACT16, EXTRACT32, 32,
+ PSIMD_MUL_S32)
+GEN_PSIMD_WIDEN_MUL_ACC(pwmaccsu_h, int16_t, uint16_t, int32_t,
+ int32_t, uint32_t, 2, EXTRACT16, EXTRACT32, 32,
+ PSIMD_MUL_SU32)
+GEN_PSIMD_WIDEN_MUL_ACC(pwmaccu_h, uint16_t, uint16_t, uint32_t,
+ uint32_t, uint32_t, 2, EXTRACT16, EXTRACT32, 32,
+ PSIMD_MUL_U32)
+
+GEN_PSIMD_WIDEN_QMUL_ACC(mqwacc, int32_t, int64_t, int64_t,
+ int64_t, uint64_t, 1, EXTRACT32, EXTRACT64,
+ 0, 0, 31, 0, 64, PSIMD_MUL_S64)
+GEN_PSIMD_WIDEN_QMUL_ACC(mqrwacc, int32_t, int64_t, int64_t,
+ int64_t, uint64_t, 1, EXTRACT32, EXTRACT64,
+ 0, 0, 31, 1LL << 30, 64, PSIMD_MUL_S64)
+
+GEN_PSIMD_WIDEN_MUL(wmul, int32_t, int32_t, int64_t, uint64_t,
+ 1, EXTRACT32, 64, PSIMD_MUL_S64)
+GEN_PSIMD_WIDEN_MUL(wmulsu, int32_t, uint32_t, int64_t, uint64_t,
+ 1, EXTRACT32, 64, PSIMD_MUL_SU64)
+GEN_PSIMD_WIDEN_MUL(wmulu, uint32_t, uint32_t, uint64_t, uint64_t,
+ 1, EXTRACT32, 64, PSIMD_MUL_U64)
+
+GEN_PSIMD_WIDEN_MUL_ACC(wmacc, int32_t, int32_t, int64_t,
+ int64_t, uint64_t, 1, EXTRACT32, EXTRACT64, 64,
+ PSIMD_MUL_S64)
+GEN_PSIMD_WIDEN_MUL_ACC(wmaccsu, int32_t, uint32_t, int64_t,
+ int64_t, uint64_t, 1, EXTRACT32, EXTRACT64, 64,
+ PSIMD_MUL_SU64)
+GEN_PSIMD_WIDEN_MUL_ACC(wmaccu, uint32_t, uint32_t, uint64_t,
+ uint64_t, uint64_t, 1, EXTRACT32, EXTRACT64, 64,
+ PSIMD_MUL_U64)
+
+GEN_PSIMD_DW_2WAY_MUL(pm2wadd_h, int16_t, int16_t, int64_t,
+ EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_S64, PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL(pm2waddsu_h, int16_t, uint16_t, int64_t,
+ EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_SU64,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL(pm2waddu_h, uint16_t, uint16_t, uint64_t,
+ EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_U64, PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL_ACC(pm2wadda_h, int16_t, int16_t, int64_t, int64_t,
+ EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_S64,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL_ACC(pm2waddasu_h, int16_t, uint16_t, int64_t,
+ int64_t, EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_SU64,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL_ACC(pm2waddau_h, uint16_t, uint16_t, uint64_t,
+ uint64_t, EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_U64,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL(pm2wadd_hx, int16_t, int16_t, int64_t,
+ EXTRACT16, 0, 1, 1, 0, PSIMD_MUL_S64, PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL_ACC(pm2wadda_hx, int16_t, int16_t, int64_t, int64_t,
+ EXTRACT16, 0, 1, 1, 0, PSIMD_MUL_S64,
+ PSIMD_COMB_ADD)
+GEN_PSIMD_DW_2WAY_MUL(pm2wsub_h, int16_t, int16_t, int64_t,
+ EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_S64, PSIMD_COMB_SUB)
+GEN_PSIMD_DW_2WAY_MUL(pm2wsub_hx, int16_t, int16_t, int64_t,
+ EXTRACT16, 0, 1, 1, 0, PSIMD_MUL_S64, PSIMD_COMB_SUB)
+GEN_PSIMD_DW_2WAY_MUL_ACC(pm2wsuba_h, int16_t, int16_t, int64_t, int64_t,
+ EXTRACT16, 0, 1, 0, 1, PSIMD_MUL_S64,
+ PSIMD_COMB_SUB)
+GEN_PSIMD_DW_2WAY_MUL_ACC(pm2wsuba_hx, int16_t, int16_t, int64_t, int64_t,
+ EXTRACT16, 0, 1, 1, 0, PSIMD_MUL_S64,
+ PSIMD_COMB_SUB)
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 18/18] target/riscv: Remove Zbkb dependency from P extension to align with the spec
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (16 preceding siblings ...)
2026-07-17 10:07 ` [PATCH v2 17/18] target/riscv: Add packed SIMD RV32 only instructions Molly Chen
@ 2026-07-17 10:07 ` Molly Chen
2026-07-29 8:43 ` [PATCH v2 00/18] target/riscv: Add support for RISC-V P Chao Liu
2026-07-29 9:32 ` Chao Liu
19 siblings, 0 replies; 31+ messages in thread
From: Molly Chen @ 2026-07-17 10:07 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
chao.liu.zevorn, Chao Liu
Cc: xiaoou, qemu-riscv, qemu-devel
Signed-off-by: Molly Chen <xiaoou@iscas.ac.cn>
---
target/riscv/tcg/insn_trans/trans_rvb.c.inc | 4 +++-
target/riscv/tcg/insn_trans/trans_rvp.c.inc | 2 +-
target/riscv/tcg/tcg-cpu.c | 6 ++----
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/target/riscv/tcg/insn_trans/trans_rvb.c.inc b/target/riscv/tcg/insn_trans/trans_rvb.c.inc
index e4dcc7c9913..af53eb4fe4b 100644
--- a/target/riscv/tcg/insn_trans/trans_rvb.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvb.c.inc
@@ -527,7 +527,9 @@ static bool trans_brev8(DisasContext *ctx, arg_brev8 *a)
static bool trans_pack(DisasContext *ctx, arg_pack *a)
{
- REQUIRE_ZBKB(ctx);
+ if (!has_ext(ctx, RVP) && !ctx->cfg_ptr->ext_zbkb) {
+ return false;
+ }
return gen_arith(ctx, a, EXT_NONE, gen_pack, NULL);
}
diff --git a/target/riscv/tcg/insn_trans/trans_rvp.c.inc b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
index e33e0ec110a..8c5b52ca970 100644
--- a/target/riscv/tcg/insn_trans/trans_rvp.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvp.c.inc
@@ -1386,4 +1386,4 @@ GEN_DWS_REG_OP(psll_dws, gen_shift, EXT_NONE, tcg_gen_shl_tl)
GEN_DWS_REG_OP(psrl_dws, gen_shift, EXT_ZERO, tcg_gen_shr_tl)
GEN_DWS_REG_OP(psra_dws, gen_shift, EXT_SIGN, tcg_gen_sar_tl)
-GEN_DW_PAIR_ARITH(ppaire_dh, REQUIRE_ZBKB(ctx); , EXT_NONE, gen_pack)
+GEN_DW_PAIR_ARITH(ppaire_dh, , EXT_NONE, gen_pack)
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 1665583accf..36b0196a626 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -563,10 +563,8 @@ static void riscv_cpu_validate_p(RISCVCPU *cpu, Error **errp)
return;
}
- if (!(cpu->cfg.ext_zmmul && cpu->cfg.ext_zba && cpu->cfg.ext_zbb &&
- cpu->cfg.ext_zbkb)) {
- error_setg(errp, "P extension requires zmmul, zba, zbb and zbkb "
- "extensions");
+ if (!(cpu->cfg.ext_zmmul && cpu->cfg.ext_zba && cpu->cfg.ext_zbb)) {
+ error_setg(errp, "P extension requires zmmul, zba and zbb extensions");
return;
}
}
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v2 00/18] target/riscv: Add support for RISC-V P
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (17 preceding siblings ...)
2026-07-17 10:07 ` [PATCH v2 18/18] target/riscv: Remove Zbkb dependency from P extension to align with the spec Molly Chen
@ 2026-07-29 8:43 ` Chao Liu
2026-07-29 9:32 ` Chao Liu
19 siblings, 0 replies; 31+ messages in thread
From: Chao Liu @ 2026-07-29 8:43 UTC (permalink / raw)
To: Molly Chen
Cc: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
qemu-riscv, qemu-devel
Hi Molly,
On Fri, Jul 17, 2026 at 10:06:53AM +0800, Molly Chen wrote:
> This series adds support for the RISC-V Packed SIMD (P) extension.
>
> The P extension defines packed-SIMD fixed-point operations intended
> for DSP-style workloads such as multimedia and signal processing.
> These instructions operate on packed subword elements within
> general-purpose registers (GPRs).
>
> The implementation follows the current development draft of the
> specification (v0.20):
>
> https://github.com/riscv/riscv-p-spec/
> or
> https://www.jhauser.us/RISCV/ext-P/
>
> Compared with v1, this version reduces implementation boilerplate by
> defining and reusing helper macros for common patterns in
> trans_rvp.c.inc and psimd_helper.c. It also consolidates the P
> extension prerequisite validation in riscv_cpu_validate_p().
>
> The Zbkb dependency has been removed to align the implementation with
> the current specification. This version also implements the
> specification-defined control of vxsat, which was missing from v1.
>
> All instructions have been functionally tested using the following
> test suite:
>
> https://github.com/mollybuild/qemu-riscv-test-uart
I believe we need to add some TCG test cases for the patches if
the latest compiler supports the P extension, we can add some cases
similar to your repo.
Thanks,
Chao
>
> The implementation focuses on functional correctness and ISA
> coverage. Performance optimizations were not considered at this
> stage.
>
> Feedback on the implementation details would be highly appreciated.
>
> Tested with:
>
> - ninja -C build test
> - make -C build check-qtest-riscv32
> - make -C build check-qtest-riscv64
> - Functional tests for all P extension instructions using
> qemu-riscv-test-uart
>
> No regressions or test failures were observed.
>
> ---
> Changes in v2:
>
> - Refactored trans_rvp.c.inc and psimd_helper.c by defining and
> reusing helper macros for common implementation patterns, reducing
> boilerplate and overall code size.
> - Moved the P extension prerequisite checks into
> riscv_cpu_validate_p().
> - Removed the Zbkb dependency to align with the current
> specification.
> - Added the specification-defined vxsat control mechanism, which was
> missing from v1.
>
> v1:
> https://lists.nongnu.org/archive/html/qemu-riscv/2026-04/msg00301.html
>
> Molly Chen (18):
> target/riscv: Add packed SIMD extension state
> target/riscv: Add packed SIMD helper framework
> target/riscv: Add packed SIMD arithmetic instructions
> target/riscv: Add packed SIMD averaging and rounding instructions
> target/riscv: Add packed SIMD absolute, difference, compare and mask
> instructions
> target/riscv: Add packed SIMD shift instructions
> target/riscv: Add packed SIMD exchange instructions
> target/riscv: Add packed SIMD horizontal reduction instructions
> target/riscv: Add packed SIMD pack, merge and count-leading
> instructions
> target/riscv: Add packed SIMD multiplication instructions
> target/riscv: Add packed SIMD multiply-accumulate instructions
> target/riscv: Add packed SIMD Q-format multiplication instructions
> target/riscv: Add packed SIMD Q-format MAC instructions
> target/riscv: Add packed SIMD two-way MAC instructions
> target/riscv: Add packed SIMD four-way MAC instructions
> target/riscv: Add packed SIMD load-replicate instructions
> target/riscv: Add packed SIMD RV32 only instructions
> target/riscv: Remove Zbkb dependency from P extension to align with
> the spec
>
> target/riscv/cpu.c | 5 +-
> target/riscv/cpu.h | 8 +
> target/riscv/cpu_bits.h | 2 +
> target/riscv/helper.h | 529 ++++
> target/riscv/insn32.decode | 829 +++++
> target/riscv/machine.c | 19 +
> target/riscv/tcg/csr.c | 39 +-
> target/riscv/tcg/insn_trans/trans_rvb.c.inc | 4 +-
> target/riscv/tcg/insn_trans/trans_rvp.c.inc | 1389 ++++++++
> target/riscv/tcg/meson.build | 3 +-
> target/riscv/tcg/psimd_helper.c | 3165 +++++++++++++++++++
> target/riscv/tcg/tcg-cpu.c | 46 +
> target/riscv/tcg/translate.c | 6 +
> 13 files changed, 6038 insertions(+), 6 deletions(-)
> create mode 100644 target/riscv/tcg/insn_trans/trans_rvp.c.inc
> create mode 100644 target/riscv/tcg/psimd_helper.c
>
>
> base-commit: 8fb307591625731060d399aca42373c02c7cb040
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v2 00/18] target/riscv: Add support for RISC-V P
2026-07-17 10:06 [PATCH v2 00/18] target/riscv: Add support for RISC-V P Molly Chen
` (18 preceding siblings ...)
2026-07-29 8:43 ` [PATCH v2 00/18] target/riscv: Add support for RISC-V P Chao Liu
@ 2026-07-29 9:32 ` Chao Liu
19 siblings, 0 replies; 31+ messages in thread
From: Chao Liu @ 2026-07-29 9:32 UTC (permalink / raw)
To: Molly Chen
Cc: palmer, alistair.francis, liwei1518, daniel.barboza, zhiwei_liu,
qemu-riscv, qemu-devel
On Fri, Jul 17, 2026 at 10:06:53AM +0800, Molly Chen wrote:
> This series adds support for the RISC-V Packed SIMD (P) extension.
>
> The P extension defines packed-SIMD fixed-point operations intended
> for DSP-style workloads such as multimedia and signal processing.
> These instructions operate on packed subword elements within
> general-purpose registers (GPRs).
>
> The implementation follows the current development draft of the
> specification (v0.20):
>
> https://github.com/riscv/riscv-p-spec/
> or
> https://www.jhauser.us/RISCV/ext-P/
>
> Compared with v1, this version reduces implementation boilerplate by
> defining and reusing helper macros for common patterns in
> trans_rvp.c.inc and psimd_helper.c. It also consolidates the P
> extension prerequisite validation in riscv_cpu_validate_p().
>
> The Zbkb dependency has been removed to align the implementation with
> the current specification. This version also implements the
> specification-defined control of vxsat, which was missing from v1.
>
> All instructions have been functionally tested using the following
> test suite:
>
> https://github.com/mollybuild/qemu-riscv-test-uart
>
> The implementation focuses on functional correctness and ISA
> coverage. Performance optimizations were not considered at this
> stage.
>
> Feedback on the implementation details would be highly appreciated.
>
> Tested with:
>
> - ninja -C build test
> - make -C build check-qtest-riscv32
> - make -C build check-qtest-riscv64
> - Functional tests for all P extension instructions using
> qemu-riscv-test-uart
>
> No regressions or test failures were observed.
>
> ---
> Changes in v2:
>
> - Refactored trans_rvp.c.inc and psimd_helper.c by defining and
> reusing helper macros for common implementation patterns, reducing
> boilerplate and overall code size.
> - Moved the P extension prerequisite checks into
> riscv_cpu_validate_p().
> - Removed the Zbkb dependency to align with the current
> specification.
> - Added the specification-defined vxsat control mechanism, which was
> missing from v1.
>
This patch set is a significant improvement over v1. I think there are still
a few common issues we can address together:
1. The line break characters '\' in the helper macros we defined need to be space-aligned.
2. Every patch is currently missing a commit body.
I think these changes are quite necessary.
Thanks,
Chao
> v1:
> https://lists.nongnu.org/archive/html/qemu-riscv/2026-04/msg00301.html
>
> Molly Chen (18):
> target/riscv: Add packed SIMD extension state
> target/riscv: Add packed SIMD helper framework
> target/riscv: Add packed SIMD arithmetic instructions
> target/riscv: Add packed SIMD averaging and rounding instructions
> target/riscv: Add packed SIMD absolute, difference, compare and mask
> instructions
> target/riscv: Add packed SIMD shift instructions
> target/riscv: Add packed SIMD exchange instructions
> target/riscv: Add packed SIMD horizontal reduction instructions
> target/riscv: Add packed SIMD pack, merge and count-leading
> instructions
> target/riscv: Add packed SIMD multiplication instructions
> target/riscv: Add packed SIMD multiply-accumulate instructions
> target/riscv: Add packed SIMD Q-format multiplication instructions
> target/riscv: Add packed SIMD Q-format MAC instructions
> target/riscv: Add packed SIMD two-way MAC instructions
> target/riscv: Add packed SIMD four-way MAC instructions
> target/riscv: Add packed SIMD load-replicate instructions
> target/riscv: Add packed SIMD RV32 only instructions
> target/riscv: Remove Zbkb dependency from P extension to align with
> the spec
>
> target/riscv/cpu.c | 5 +-
> target/riscv/cpu.h | 8 +
> target/riscv/cpu_bits.h | 2 +
> target/riscv/helper.h | 529 ++++
> target/riscv/insn32.decode | 829 +++++
> target/riscv/machine.c | 19 +
> target/riscv/tcg/csr.c | 39 +-
> target/riscv/tcg/insn_trans/trans_rvb.c.inc | 4 +-
> target/riscv/tcg/insn_trans/trans_rvp.c.inc | 1389 ++++++++
> target/riscv/tcg/meson.build | 3 +-
> target/riscv/tcg/psimd_helper.c | 3165 +++++++++++++++++++
> target/riscv/tcg/tcg-cpu.c | 46 +
> target/riscv/tcg/translate.c | 6 +
> 13 files changed, 6038 insertions(+), 6 deletions(-)
> create mode 100644 target/riscv/tcg/insn_trans/trans_rvp.c.inc
> create mode 100644 target/riscv/tcg/psimd_helper.c
>
>
> base-commit: 8fb307591625731060d399aca42373c02c7cb040
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 31+ messages in thread