[PATCH v2 02/18] target/riscv: Add packed SIMD helper framework

Molly Chen <[email protected]>
Newsgroups org.nongnu.qemu-riscv,org.nongnu.qemu-devel
Message-ID <e3775ec9235fa974e9a318edf1836cdaab197e27.1784280142.git.xiaoou@iscas.ac.cn>
Signed-off-by: Molly Chen <[email protected]>
---
 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.