aboutsummaryrefslogtreecommitdiffstats
path: root/target/riscv/insn_trans
diff options
context:
space:
mode:
authorTimos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>2023-10-10 11:40:56 +0000
committerTimos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>2023-10-10 11:40:56 +0000
commite02cda008591317b1625707ff8e115a4841aa889 (patch)
treeaee302e3cf8b59ec2d32ec481be3d1afddfc8968 /target/riscv/insn_trans
parentcc668e6b7e0ffd8c9d130513d12053cf5eda1d3b (diff)
Introduce Virtio-loopback epsilon release:
Epsilon release introduces a new compatibility layer which make virtio-loopback design to work with QEMU and rust-vmm vhost-user backend without require any changes. Signed-off-by: Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com> Change-Id: I52e57563e08a7d0bdc002f8e928ee61ba0c53dd9
Diffstat (limited to 'target/riscv/insn_trans')
-rw-r--r--target/riscv/insn_trans/trans_privileged.c.inc128
-rw-r--r--target/riscv/insn_trans/trans_rva.c.inc226
-rw-r--r--target/riscv/insn_trans/trans_rvb.c.inc506
-rw-r--r--target/riscv/insn_trans/trans_rvd.c.inc449
-rw-r--r--target/riscv/insn_trans/trans_rvf.c.inc473
-rw-r--r--target/riscv/insn_trans/trans_rvh.c.inc186
-rw-r--r--target/riscv/insn_trans/trans_rvi.c.inc577
-rw-r--r--target/riscv/insn_trans/trans_rvm.c.inc271
-rw-r--r--target/riscv/insn_trans/trans_rvv.c.inc2867
9 files changed, 5683 insertions, 0 deletions
diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc
new file mode 100644
index 000000000..75c6ef80a
--- /dev/null
+++ b/target/riscv/insn_trans/trans_privileged.c.inc
@@ -0,0 +1,128 @@
+/*
+ * RISC-V translation routines for the RISC-V privileged instructions.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static bool trans_ecall(DisasContext *ctx, arg_ecall *a)
+{
+ /* always generates U-level ECALL, fixed in do_interrupt handler */
+ generate_exception(ctx, RISCV_EXCP_U_ECALL);
+ return true;
+}
+
+static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a)
+{
+ target_ulong ebreak_addr = ctx->base.pc_next;
+ target_ulong pre_addr = ebreak_addr - 4;
+ target_ulong post_addr = ebreak_addr + 4;
+ uint32_t pre = 0;
+ uint32_t ebreak = 0;
+ uint32_t post = 0;
+
+ /*
+ * The RISC-V semihosting spec specifies the following
+ * three-instruction sequence to flag a semihosting call:
+ *
+ * slli zero, zero, 0x1f 0x01f01013
+ * ebreak 0x00100073
+ * srai zero, zero, 0x7 0x40705013
+ *
+ * The two shift operations on the zero register are no-ops, used
+ * here to signify a semihosting exception, rather than a breakpoint.
+ *
+ * Uncompressed instructions are required so that the sequence is easy
+ * to validate.
+ *
+ * The three instructions are required to lie in the same page so
+ * that no exception will be raised when fetching them.
+ */
+
+ if ((pre_addr & TARGET_PAGE_MASK) == (post_addr & TARGET_PAGE_MASK)) {
+ pre = opcode_at(&ctx->base, pre_addr);
+ ebreak = opcode_at(&ctx->base, ebreak_addr);
+ post = opcode_at(&ctx->base, post_addr);
+ }
+
+ if (pre == 0x01f01013 && ebreak == 0x00100073 && post == 0x40705013) {
+ generate_exception(ctx, RISCV_EXCP_SEMIHOST);
+ } else {
+ generate_exception(ctx, RISCV_EXCP_BREAKPOINT);
+ }
+ return true;
+}
+
+static bool trans_uret(DisasContext *ctx, arg_uret *a)
+{
+ return false;
+}
+
+static bool trans_sret(DisasContext *ctx, arg_sret *a)
+{
+#ifndef CONFIG_USER_ONLY
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
+
+ if (has_ext(ctx, RVS)) {
+ gen_helper_sret(cpu_pc, cpu_env, cpu_pc);
+ tcg_gen_exit_tb(NULL, 0); /* no chaining */
+ ctx->base.is_jmp = DISAS_NORETURN;
+ } else {
+ return false;
+ }
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool trans_mret(DisasContext *ctx, arg_mret *a)
+{
+#ifndef CONFIG_USER_ONLY
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
+ gen_helper_mret(cpu_pc, cpu_env, cpu_pc);
+ tcg_gen_exit_tb(NULL, 0); /* no chaining */
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool trans_wfi(DisasContext *ctx, arg_wfi *a)
+{
+#ifndef CONFIG_USER_ONLY
+ tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
+ gen_helper_wfi(cpu_env);
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool trans_sfence_vma(DisasContext *ctx, arg_sfence_vma *a)
+{
+#ifndef CONFIG_USER_ONLY
+ gen_helper_tlb_flush(cpu_env);
+ return true;
+#endif
+ return false;
+}
+
+static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a)
+{
+ return false;
+}
diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc
new file mode 100644
index 000000000..40fe132b0
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rva.c.inc
@@ -0,0 +1,226 @@
+/*
+ * RISC-V translation routines for the RV64A Standard Extension.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static bool gen_lr(DisasContext *ctx, arg_atomic *a, MemOp mop)
+{
+ TCGv src1 = get_gpr(ctx, a->rs1, EXT_ZERO);
+
+ if (a->rl) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
+ }
+ src1 = gen_pm_adjust_address(ctx, src1);
+ tcg_gen_qemu_ld_tl(load_val, src1, ctx->mem_idx, mop);
+ if (a->aq) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
+ }
+
+ /* Put addr in load_res, data in load_val. */
+ tcg_gen_mov_tl(load_res, src1);
+ gen_set_gpr(ctx, a->rd, load_val);
+
+ return true;
+}
+
+static bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop)
+{
+ TCGv dest, src1, src2;
+ TCGLabel *l1 = gen_new_label();
+ TCGLabel *l2 = gen_new_label();
+
+ src1 = get_gpr(ctx, a->rs1, EXT_ZERO);
+ src1 = gen_pm_adjust_address(ctx, src1);
+ tcg_gen_brcond_tl(TCG_COND_NE, load_res, src1, l1);
+
+ /*
+ * Note that the TCG atomic primitives are SC,
+ * so we can ignore AQ/RL along this path.
+ */
+ dest = dest_gpr(ctx, a->rd);
+ src2 = get_gpr(ctx, a->rs2, EXT_NONE);
+ tcg_gen_atomic_cmpxchg_tl(dest, load_res, load_val, src2,
+ ctx->mem_idx, mop);
+ tcg_gen_setcond_tl(TCG_COND_NE, dest, dest, load_val);
+ gen_set_gpr(ctx, a->rd, dest);
+ tcg_gen_br(l2);
+
+ gen_set_label(l1);
+ /*
+ * Address comparison failure. However, we still need to
+ * provide the memory barrier implied by AQ/RL.
+ */
+ tcg_gen_mb(TCG_MO_ALL + a->aq * TCG_BAR_LDAQ + a->rl * TCG_BAR_STRL);
+ gen_set_gpr(ctx, a->rd, tcg_constant_tl(1));
+
+ gen_set_label(l2);
+ /*
+ * Clear the load reservation, since an SC must fail if there is
+ * an SC to any address, in between an LR and SC pair.
+ */
+ tcg_gen_movi_tl(load_res, -1);
+
+ return true;
+}
+
+static bool gen_amo(DisasContext *ctx, arg_atomic *a,
+ void(*func)(TCGv, TCGv, TCGv, TCGArg, MemOp),
+ MemOp mop)
+{
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);
+ TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
+
+ src1 = gen_pm_adjust_address(ctx, src1);
+ func(dest, src1, src2, ctx->mem_idx, mop);
+
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_lr_w(DisasContext *ctx, arg_lr_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_lr(ctx, a, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_sc_w(DisasContext *ctx, arg_sc_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_sc(ctx, a, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amoswap_w(DisasContext *ctx, arg_amoswap_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amoadd_w(DisasContext *ctx, arg_amoadd_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amoxor_w(DisasContext *ctx, arg_amoxor_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amoand_w(DisasContext *ctx, arg_amoand_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amoor_w(DisasContext *ctx, arg_amoor_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amomin_w(DisasContext *ctx, arg_amomin_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amomax_w(DisasContext *ctx, arg_amomax_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amominu_w(DisasContext *ctx, arg_amominu_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amomaxu_w(DisasContext *ctx, arg_amomaxu_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_lr_d(DisasContext *ctx, arg_lr_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_lr(ctx, a, MO_ALIGN | MO_TEQ);
+}
+
+static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_sc(ctx, a, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amoswap_d(DisasContext *ctx, arg_amoswap_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amoadd_d(DisasContext *ctx, arg_amoadd_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amoxor_d(DisasContext *ctx, arg_amoxor_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amoand_d(DisasContext *ctx, arg_amoand_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amoor_d(DisasContext *ctx, arg_amoor_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amomin_d(DisasContext *ctx, arg_amomin_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amomax_d(DisasContext *ctx, arg_amomax_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amominu_d(DisasContext *ctx, arg_amominu_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amomaxu_d(DisasContext *ctx, arg_amomaxu_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TEQ));
+}
diff --git a/target/riscv/insn_trans/trans_rvb.c.inc b/target/riscv/insn_trans/trans_rvb.c.inc
new file mode 100644
index 000000000..c8d31907c
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvb.c.inc
@@ -0,0 +1,506 @@
+/*
+ * RISC-V translation routines for the Zb[abcs] Standard Extension.
+ *
+ * Copyright (c) 2020 Kito Cheng, kito.cheng@sifive.com
+ * Copyright (c) 2020 Frank Chang, frank.chang@sifive.com
+ * Copyright (c) 2021 Philipp Tomsich, philipp.tomsich@vrull.eu
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define REQUIRE_ZBA(ctx) do { \
+ if (!RISCV_CPU(ctx->cs)->cfg.ext_zba) { \
+ return false; \
+ } \
+} while (0)
+
+#define REQUIRE_ZBB(ctx) do { \
+ if (!RISCV_CPU(ctx->cs)->cfg.ext_zbb) { \
+ return false; \
+ } \
+} while (0)
+
+#define REQUIRE_ZBC(ctx) do { \
+ if (!RISCV_CPU(ctx->cs)->cfg.ext_zbc) { \
+ return false; \
+ } \
+} while (0)
+
+#define REQUIRE_ZBS(ctx) do { \
+ if (!RISCV_CPU(ctx->cs)->cfg.ext_zbs) { \
+ return false; \
+ } \
+} while (0)
+
+static void gen_clz(TCGv ret, TCGv arg1)
+{
+ tcg_gen_clzi_tl(ret, arg1, TARGET_LONG_BITS);
+}
+
+static void gen_clzw(TCGv ret, TCGv arg1)
+{
+ TCGv t = tcg_temp_new();
+ tcg_gen_shli_tl(t, arg1, 32);
+ tcg_gen_clzi_tl(ret, t, 32);
+ tcg_temp_free(t);
+}
+
+static bool trans_clz(DisasContext *ctx, arg_clz *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_unary_per_ol(ctx, a, EXT_NONE, gen_clz, gen_clzw);
+}
+
+static void gen_ctz(TCGv ret, TCGv arg1)
+{
+ tcg_gen_ctzi_tl(ret, arg1, TARGET_LONG_BITS);
+}
+
+static void gen_ctzw(TCGv ret, TCGv arg1)
+{
+ tcg_gen_ctzi_tl(ret, arg1, 32);
+}
+
+static bool trans_ctz(DisasContext *ctx, arg_ctz *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_unary_per_ol(ctx, a, EXT_ZERO, gen_ctz, gen_ctzw);
+}
+
+static bool trans_cpop(DisasContext *ctx, arg_cpop *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_ZERO, tcg_gen_ctpop_tl);
+}
+
+static bool trans_andn(DisasContext *ctx, arg_andn *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_andc_tl);
+}
+
+static bool trans_orn(DisasContext *ctx, arg_orn *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_orc_tl);
+}
+
+static bool trans_xnor(DisasContext *ctx, arg_xnor *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_eqv_tl);
+}
+
+static bool trans_min(DisasContext *ctx, arg_min *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_arith(ctx, a, EXT_SIGN, tcg_gen_smin_tl);
+}
+
+static bool trans_max(DisasContext *ctx, arg_max *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_arith(ctx, a, EXT_SIGN, tcg_gen_smax_tl);
+}
+
+static bool trans_minu(DisasContext *ctx, arg_minu *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_arith(ctx, a, EXT_SIGN, tcg_gen_umin_tl);
+}
+
+static bool trans_maxu(DisasContext *ctx, arg_maxu *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_arith(ctx, a, EXT_SIGN, tcg_gen_umax_tl);
+}
+
+static bool trans_sext_b(DisasContext *ctx, arg_sext_b *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext8s_tl);
+}
+
+static bool trans_sext_h(DisasContext *ctx, arg_sext_h *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext16s_tl);
+}
+
+static void gen_sbop_mask(TCGv ret, TCGv shamt)
+{
+ tcg_gen_movi_tl(ret, 1);
+ tcg_gen_shl_tl(ret, ret, shamt);
+}
+
+static void gen_bset(TCGv ret, TCGv arg1, TCGv shamt)
+{
+ TCGv t = tcg_temp_new();
+
+ gen_sbop_mask(t, shamt);
+ tcg_gen_or_tl(ret, arg1, t);
+
+ tcg_temp_free(t);
+}
+
+static bool trans_bset(DisasContext *ctx, arg_bset *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift(ctx, a, EXT_NONE, gen_bset);
+}
+
+static bool trans_bseti(DisasContext *ctx, arg_bseti *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bset);
+}
+
+static void gen_bclr(TCGv ret, TCGv arg1, TCGv shamt)
+{
+ TCGv t = tcg_temp_new();
+
+ gen_sbop_mask(t, shamt);
+ tcg_gen_andc_tl(ret, arg1, t);
+
+ tcg_temp_free(t);
+}
+
+static bool trans_bclr(DisasContext *ctx, arg_bclr *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift(ctx, a, EXT_NONE, gen_bclr);
+}
+
+static bool trans_bclri(DisasContext *ctx, arg_bclri *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bclr);
+}
+
+static void gen_binv(TCGv ret, TCGv arg1, TCGv shamt)
+{
+ TCGv t = tcg_temp_new();
+
+ gen_sbop_mask(t, shamt);
+ tcg_gen_xor_tl(ret, arg1, t);
+
+ tcg_temp_free(t);
+}
+
+static bool trans_binv(DisasContext *ctx, arg_binv *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift(ctx, a, EXT_NONE, gen_binv);
+}
+
+static bool trans_binvi(DisasContext *ctx, arg_binvi *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_binv);
+}
+
+static void gen_bext(TCGv ret, TCGv arg1, TCGv shamt)
+{
+ tcg_gen_shr_tl(ret, arg1, shamt);
+ tcg_gen_andi_tl(ret, ret, 1);
+}
+
+static bool trans_bext(DisasContext *ctx, arg_bext *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift(ctx, a, EXT_NONE, gen_bext);
+}
+
+static bool trans_bexti(DisasContext *ctx, arg_bexti *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bext);
+}
+
+static void gen_rorw(TCGv ret, TCGv arg1, TCGv arg2)
+{
+ TCGv_i32 t1 = tcg_temp_new_i32();
+ TCGv_i32 t2 = tcg_temp_new_i32();
+
+ /* truncate to 32-bits */
+ tcg_gen_trunc_tl_i32(t1, arg1);
+ tcg_gen_trunc_tl_i32(t2, arg2);
+
+ tcg_gen_rotr_i32(t1, t1, t2);
+
+ /* sign-extend 64-bits */
+ tcg_gen_ext_i32_tl(ret, t1);
+
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t2);
+}
+
+static bool trans_ror(DisasContext *ctx, arg_ror *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_shift_per_ol(ctx, a, EXT_NONE, tcg_gen_rotr_tl, gen_rorw);
+}
+
+static void gen_roriw(TCGv ret, TCGv arg1, target_long shamt)
+{
+ TCGv_i32 t1 = tcg_temp_new_i32();
+
+ tcg_gen_trunc_tl_i32(t1, arg1);
+ tcg_gen_rotri_i32(t1, t1, shamt);
+ tcg_gen_ext_i32_tl(ret, t1);
+
+ tcg_temp_free_i32(t1);
+}
+
+static bool trans_rori(DisasContext *ctx, arg_rori *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE,
+ tcg_gen_rotri_tl, gen_roriw);
+}
+
+static void gen_rolw(TCGv ret, TCGv arg1, TCGv arg2)
+{
+ TCGv_i32 t1 = tcg_temp_new_i32();
+ TCGv_i32 t2 = tcg_temp_new_i32();
+
+ /* truncate to 32-bits */
+ tcg_gen_trunc_tl_i32(t1, arg1);
+ tcg_gen_trunc_tl_i32(t2, arg2);
+
+ tcg_gen_rotl_i32(t1, t1, t2);
+
+ /* sign-extend 64-bits */
+ tcg_gen_ext_i32_tl(ret, t1);
+
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t2);
+}
+
+static bool trans_rol(DisasContext *ctx, arg_rol *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_shift_per_ol(ctx, a, EXT_NONE, tcg_gen_rotl_tl, gen_rolw);
+}
+
+static void gen_rev8_32(TCGv ret, TCGv src1)
+{
+ tcg_gen_bswap32_tl(ret, src1, TCG_BSWAP_OS);
+}
+
+static bool trans_rev8_32(DisasContext *ctx, arg_rev8_32 *a)
+{
+ REQUIRE_32BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_NONE, gen_rev8_32);
+}
+
+static bool trans_rev8_64(DisasContext *ctx, arg_rev8_64 *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_NONE, tcg_gen_bswap_tl);
+}
+
+static void gen_orc_b(TCGv ret, TCGv source1)
+{
+ TCGv tmp = tcg_temp_new();
+ TCGv low7 = tcg_constant_tl(dup_const_tl(MO_8, 0x7f));
+
+ /* Set msb in each byte if the byte was non-zero. */
+ tcg_gen_and_tl(tmp, source1, low7);
+ tcg_gen_add_tl(tmp, tmp, low7);
+ tcg_gen_or_tl(tmp, tmp, source1);
+
+ /* Extract the msb to the lsb in each byte */
+ tcg_gen_andc_tl(tmp, tmp, low7);
+ tcg_gen_shri_tl(tmp, tmp, 7);
+
+ /* Replicate the lsb of each byte across the byte. */
+ tcg_gen_muli_tl(ret, tmp, 0xff);
+
+ tcg_temp_free(tmp);
+}
+
+static bool trans_orc_b(DisasContext *ctx, arg_orc_b *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_ZERO, gen_orc_b);
+}
+
+#define GEN_SHADD(SHAMT) \
+static void gen_sh##SHAMT##add(TCGv ret, TCGv arg1, TCGv arg2) \
+{ \
+ TCGv t = tcg_temp_new(); \
+ \
+ tcg_gen_shli_tl(t, arg1, SHAMT); \
+ tcg_gen_add_tl(ret, t, arg2); \
+ \
+ tcg_temp_free(t); \
+}
+
+GEN_SHADD(1)
+GEN_SHADD(2)
+GEN_SHADD(3)
+
+#define GEN_TRANS_SHADD(SHAMT) \
+static bool trans_sh##SHAMT##add(DisasContext *ctx, arg_sh##SHAMT##add *a) \
+{ \
+ REQUIRE_ZBA(ctx); \
+ return gen_arith(ctx, a, EXT_NONE, gen_sh##SHAMT##add); \
+}
+
+GEN_TRANS_SHADD(1)
+GEN_TRANS_SHADD(2)
+GEN_TRANS_SHADD(3)
+
+static bool trans_zext_h_32(DisasContext *ctx, arg_zext_h_32 *a)
+{
+ REQUIRE_32BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext16u_tl);
+}
+
+static bool trans_zext_h_64(DisasContext *ctx, arg_zext_h_64 *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext16u_tl);
+}
+
+static bool trans_clzw(DisasContext *ctx, arg_clzw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_NONE, gen_clzw);
+}
+
+static bool trans_ctzw(DisasContext *ctx, arg_ctzw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_ZERO, gen_ctzw);
+}
+
+static bool trans_cpopw(DisasContext *ctx, arg_cpopw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_unary(ctx, a, EXT_ZERO, tcg_gen_ctpop_tl);
+}
+
+static bool trans_rorw(DisasContext *ctx, arg_rorw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift(ctx, a, EXT_NONE, gen_rorw);
+}
+
+static bool trans_roriw(DisasContext *ctx, arg_roriw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_roriw);
+}
+
+static bool trans_rolw(DisasContext *ctx, arg_rolw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift(ctx, a, EXT_NONE, gen_rolw);
+}
+
+#define GEN_SHADD_UW(SHAMT) \
+static void gen_sh##SHAMT##add_uw(TCGv ret, TCGv arg1, TCGv arg2) \
+{ \
+ TCGv t = tcg_temp_new(); \
+ \
+ tcg_gen_ext32u_tl(t, arg1); \
+ \
+ tcg_gen_shli_tl(t, t, SHAMT); \
+ tcg_gen_add_tl(ret, t, arg2); \
+ \
+ tcg_temp_free(t); \
+}
+
+GEN_SHADD_UW(1)
+GEN_SHADD_UW(2)
+GEN_SHADD_UW(3)
+
+#define GEN_TRANS_SHADD_UW(SHAMT) \
+static bool trans_sh##SHAMT##add_uw(DisasContext *ctx, \
+ arg_sh##SHAMT##add_uw *a) \
+{ \
+ REQUIRE_64BIT(ctx); \
+ REQUIRE_ZBA(ctx); \
+ return gen_arith(ctx, a, EXT_NONE, gen_sh##SHAMT##add_uw); \
+}
+
+GEN_TRANS_SHADD_UW(1)
+GEN_TRANS_SHADD_UW(2)
+GEN_TRANS_SHADD_UW(3)
+
+static void gen_add_uw(TCGv ret, TCGv arg1, TCGv arg2)
+{
+ TCGv t = tcg_temp_new();
+ tcg_gen_ext32u_tl(t, arg1);
+ tcg_gen_add_tl(ret, t, arg2);
+ tcg_temp_free(t);
+}
+
+static bool trans_add_uw(DisasContext *ctx, arg_add_uw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBA(ctx);
+ return gen_arith(ctx, a, EXT_NONE, gen_add_uw);
+}
+
+static void gen_slli_uw(TCGv dest, TCGv src, target_long shamt)
+{
+ tcg_gen_deposit_z_tl(dest, src, shamt, MIN(32, TARGET_LONG_BITS - shamt));
+}
+
+static bool trans_slli_uw(DisasContext *ctx, arg_slli_uw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBA(ctx);
+ return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_slli_uw);
+}
+
+static bool trans_clmul(DisasContext *ctx, arg_clmul *a)
+{
+ REQUIRE_ZBC(ctx);
+ return gen_arith(ctx, a, EXT_NONE, gen_helper_clmul);
+}
+
+static void gen_clmulh(TCGv dst, TCGv src1, TCGv src2)
+{
+ gen_helper_clmulr(dst, src1, src2);
+ tcg_gen_shri_tl(dst, dst, 1);
+}
+
+static bool trans_clmulh(DisasContext *ctx, arg_clmulr *a)
+{
+ REQUIRE_ZBC(ctx);
+ return gen_arith(ctx, a, EXT_NONE, gen_clmulh);
+}
+
+static bool trans_clmulr(DisasContext *ctx, arg_clmulh *a)
+{
+ REQUIRE_ZBC(ctx);
+ return gen_arith(ctx, a, EXT_NONE, gen_helper_clmulr);
+}
diff --git a/target/riscv/insn_trans/trans_rvd.c.inc b/target/riscv/insn_trans/trans_rvd.c.inc
new file mode 100644
index 000000000..64fb0046f
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvd.c.inc
@@ -0,0 +1,449 @@
+/*
+ * RISC-V translation routines for the RV64D Standard Extension.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static bool trans_fld(DisasContext *ctx, arg_fld *a)
+{
+ TCGv addr;
+
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ if (a->imm) {
+ TCGv temp = temp_new(ctx);
+ tcg_gen_addi_tl(temp, addr, a->imm);
+ addr = temp;
+ }
+ addr = gen_pm_adjust_address(ctx, addr);
+
+ tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, MO_TEQ);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
+{
+ TCGv addr;
+
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ if (a->imm) {
+ TCGv temp = temp_new(ctx);
+ tcg_gen_addi_tl(temp, addr, a->imm);
+ addr = temp;
+ }
+ addr = gen_pm_adjust_address(ctx, addr);
+
+ tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEQ);
+
+ return true;
+}
+
+static bool trans_fmadd_d(DisasContext *ctx, arg_fmadd_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmadd_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmsub_d(DisasContext *ctx, arg_fmsub_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmsub_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fnmsub_d(DisasContext *ctx, arg_fnmsub_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fnmsub_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fnmadd_d(DisasContext *ctx, arg_fnmadd_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fnmadd_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fadd_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fsub_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmul_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fdiv_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fsqrt_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnj_d(DisasContext *ctx, arg_fsgnj_d *a)
+{
+ if (a->rs1 == a->rs2) { /* FMOV */
+ tcg_gen_mov_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1]);
+ } else {
+ tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rs2],
+ cpu_fpr[a->rs1], 0, 63);
+ }
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnjn_d(DisasContext *ctx, arg_fsgnjn_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ if (a->rs1 == a->rs2) { /* FNEG */
+ tcg_gen_xori_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], INT64_MIN);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ tcg_gen_not_i64(t0, cpu_fpr[a->rs2]);
+ tcg_gen_deposit_i64(cpu_fpr[a->rd], t0, cpu_fpr[a->rs1], 0, 63);
+ tcg_temp_free_i64(t0);
+ }
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnjx_d(DisasContext *ctx, arg_fsgnjx_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ if (a->rs1 == a->rs2) { /* FABS */
+ tcg_gen_andi_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], ~INT64_MIN);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ tcg_gen_andi_i64(t0, cpu_fpr[a->rs2], INT64_MIN);
+ tcg_gen_xor_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], t0);
+ tcg_temp_free_i64(t0);
+ }
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_helper_fmin_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_helper_fmax_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_s_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_d_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_feq_d(DisasContext *ctx, arg_feq_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_feq_d(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_flt_d(DisasContext *ctx, arg_flt_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_flt_d(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fle_d(DisasContext *ctx, arg_fle_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_fle_d(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_fclass_d(dest, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_w_d(DisasContext *ctx, arg_fcvt_w_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_w_d(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_wu_d(DisasContext *ctx, arg_fcvt_wu_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_wu_d(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_d_w(DisasContext *ctx, arg_fcvt_d_w *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_d_w(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_d_wu(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_l_d(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_lu_d(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fmv_x_d(DisasContext *ctx, arg_fmv_x_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+#ifdef TARGET_RISCV64
+ gen_set_gpr(ctx, a->rd, cpu_fpr[a->rs1]);
+ return true;
+#else
+ qemu_build_not_reached();
+#endif
+}
+
+static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_d_l(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_d_lu(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+#ifdef TARGET_RISCV64
+ tcg_gen_mov_tl(cpu_fpr[a->rd], get_gpr(ctx, a->rs1, EXT_NONE));
+ mark_fs_dirty(ctx);
+ return true;
+#else
+ qemu_build_not_reached();
+#endif
+}
diff --git a/target/riscv/insn_trans/trans_rvf.c.inc b/target/riscv/insn_trans/trans_rvf.c.inc
new file mode 100644
index 000000000..b5459249c
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvf.c.inc
@@ -0,0 +1,473 @@
+/*
+ * RISC-V translation routines for the RV64F Standard Extension.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define REQUIRE_FPU do {\
+ if (ctx->mstatus_fs == 0) \
+ return false; \
+} while (0)
+
+static bool trans_flw(DisasContext *ctx, arg_flw *a)
+{
+ TCGv_i64 dest;
+ TCGv addr;
+
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ if (a->imm) {
+ TCGv temp = temp_new(ctx);
+ tcg_gen_addi_tl(temp, addr, a->imm);
+ addr = temp;
+ }
+ addr = gen_pm_adjust_address(ctx, addr);
+
+ dest = cpu_fpr[a->rd];
+ tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_TEUL);
+ gen_nanbox_s(dest, dest);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsw(DisasContext *ctx, arg_fsw *a)
+{
+ TCGv addr;
+
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ if (a->imm) {
+ TCGv temp = tcg_temp_new();
+ tcg_gen_addi_tl(temp, addr, a->imm);
+ addr = temp;
+ }
+ addr = gen_pm_adjust_address(ctx, addr);
+
+ tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUL);
+
+ return true;
+}
+
+static bool trans_fmadd_s(DisasContext *ctx, arg_fmadd_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmadd_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmsub_s(DisasContext *ctx, arg_fmsub_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmsub_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fnmsub_s(DisasContext *ctx, arg_fnmsub_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fnmsub_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fnmadd_s(DisasContext *ctx, arg_fnmadd_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fnmadd_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fadd_s(DisasContext *ctx, arg_fadd_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fadd_s(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsub_s(DisasContext *ctx, arg_fsub_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fsub_s(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmul_s(DisasContext *ctx, arg_fmul_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmul_s(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fdiv_s(DisasContext *ctx, arg_fdiv_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fdiv_s(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsqrt_s(DisasContext *ctx, arg_fsqrt_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fsqrt_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnj_s(DisasContext *ctx, arg_fsgnj_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ if (a->rs1 == a->rs2) { /* FMOV */
+ gen_check_nanbox_s(cpu_fpr[a->rd], cpu_fpr[a->rs1]);
+ } else { /* FSGNJ */
+ TCGv_i64 rs1 = tcg_temp_new_i64();
+ TCGv_i64 rs2 = tcg_temp_new_i64();
+
+ gen_check_nanbox_s(rs1, cpu_fpr[a->rs1]);
+ gen_check_nanbox_s(rs2, cpu_fpr[a->rs2]);
+
+ /* This formulation retains the nanboxing of rs2. */
+ tcg_gen_deposit_i64(cpu_fpr[a->rd], rs2, rs1, 0, 31);
+ tcg_temp_free_i64(rs1);
+ tcg_temp_free_i64(rs2);
+ }
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnjn_s(DisasContext *ctx, arg_fsgnjn_s *a)
+{
+ TCGv_i64 rs1, rs2, mask;
+
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ rs1 = tcg_temp_new_i64();
+ gen_check_nanbox_s(rs1, cpu_fpr[a->rs1]);
+
+ if (a->rs1 == a->rs2) { /* FNEG */
+ tcg_gen_xori_i64(cpu_fpr[a->rd], rs1, MAKE_64BIT_MASK(31, 1));
+ } else {
+ rs2 = tcg_temp_new_i64();
+ gen_check_nanbox_s(rs2, cpu_fpr[a->rs2]);
+
+ /*
+ * Replace bit 31 in rs1 with inverse in rs2.
+ * This formulation retains the nanboxing of rs1.
+ */
+ mask = tcg_constant_i64(~MAKE_64BIT_MASK(31, 1));
+ tcg_gen_nor_i64(rs2, rs2, mask);
+ tcg_gen_and_i64(rs1, mask, rs1);
+ tcg_gen_or_i64(cpu_fpr[a->rd], rs1, rs2);
+
+ tcg_temp_free_i64(rs2);
+ }
+ tcg_temp_free_i64(rs1);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnjx_s(DisasContext *ctx, arg_fsgnjx_s *a)
+{
+ TCGv_i64 rs1, rs2;
+
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ rs1 = tcg_temp_new_i64();
+ gen_check_nanbox_s(rs1, cpu_fpr[a->rs1]);
+
+ if (a->rs1 == a->rs2) { /* FABS */
+ tcg_gen_andi_i64(cpu_fpr[a->rd], rs1, ~MAKE_64BIT_MASK(31, 1));
+ } else {
+ rs2 = tcg_temp_new_i64();
+ gen_check_nanbox_s(rs2, cpu_fpr[a->rs2]);
+
+ /*
+ * Xor bit 31 in rs1 with that in rs2.
+ * This formulation retains the nanboxing of rs1.
+ */
+ tcg_gen_andi_i64(rs2, rs2, MAKE_64BIT_MASK(31, 1));
+ tcg_gen_xor_i64(cpu_fpr[a->rd], rs1, rs2);
+
+ tcg_temp_free_i64(rs2);
+ }
+ tcg_temp_free_i64(rs1);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmin_s(DisasContext *ctx, arg_fmin_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_helper_fmin_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmax_s(DisasContext *ctx, arg_fmax_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_helper_fmax_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_w_s(DisasContext *ctx, arg_fcvt_w_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_w_s(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_wu_s(DisasContext *ctx, arg_fcvt_wu_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_wu_s(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fmv_x_w(DisasContext *ctx, arg_fmv_x_w *a)
+{
+ /* NOTE: This was FMV.X.S in an earlier version of the ISA spec! */
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+#if defined(TARGET_RISCV64)
+ tcg_gen_ext32s_tl(dest, cpu_fpr[a->rs1]);
+#else
+ tcg_gen_extrl_i64_i32(dest, cpu_fpr[a->rs1]);
+#endif
+
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_feq_s(DisasContext *ctx, arg_feq_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_feq_s(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_flt_s(DisasContext *ctx, arg_flt_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_flt_s(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fle_s(DisasContext *ctx, arg_fle_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_fle_s(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fclass_s(DisasContext *ctx, arg_fclass_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_fclass_s(dest, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_s_w(DisasContext *ctx, arg_fcvt_s_w *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_s_w(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_s_wu(DisasContext *ctx, arg_fcvt_s_wu *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_s_wu(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmv_w_x(DisasContext *ctx, arg_fmv_w_x *a)
+{
+ /* NOTE: This was FMV.S.X in an earlier version of the ISA spec! */
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
+
+ tcg_gen_extu_tl_i64(cpu_fpr[a->rd], src);
+ gen_nanbox_s(cpu_fpr[a->rd], cpu_fpr[a->rd]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_l_s(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_lu_s(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_s_l(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_s_lu(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
diff --git a/target/riscv/insn_trans/trans_rvh.c.inc b/target/riscv/insn_trans/trans_rvh.c.inc
new file mode 100644
index 000000000..ecbf77ff9
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvh.c.inc
@@ -0,0 +1,186 @@
+/*
+ * RISC-V translation routines for the RVXI Base Integer Instruction Set.
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CONFIG_USER_ONLY
+static bool check_access(DisasContext *ctx)
+{
+ if (!ctx->hlsx) {
+ if (ctx->virt_enabled) {
+ generate_exception(ctx, RISCV_EXCP_VIRT_INSTRUCTION_FAULT);
+ } else {
+ generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST);
+ }
+ return false;
+ }
+ return true;
+}
+#endif
+
+static bool do_hlv(DisasContext *ctx, arg_r2 *a, MemOp mop)
+{
+#ifdef CONFIG_USER_ONLY
+ return false;
+#else
+ if (check_access(ctx)) {
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ int mem_idx = ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
+ tcg_gen_qemu_ld_tl(dest, addr, mem_idx, mop);
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+ return true;
+#endif
+}
+
+static bool trans_hlv_b(DisasContext *ctx, arg_hlv_b *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hlv(ctx, a, MO_SB);
+}
+
+static bool trans_hlv_h(DisasContext *ctx, arg_hlv_h *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hlv(ctx, a, MO_TESW);
+}
+
+static bool trans_hlv_w(DisasContext *ctx, arg_hlv_w *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hlv(ctx, a, MO_TESL);
+}
+
+static bool trans_hlv_bu(DisasContext *ctx, arg_hlv_bu *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hlv(ctx, a, MO_UB);
+}
+
+static bool trans_hlv_hu(DisasContext *ctx, arg_hlv_hu *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hlv(ctx, a, MO_TEUW);
+}
+
+static bool do_hsv(DisasContext *ctx, arg_r2_s *a, MemOp mop)
+{
+#ifdef CONFIG_USER_ONLY
+ return false;
+#else
+ if (check_access(ctx)) {
+ TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ TCGv data = get_gpr(ctx, a->rs2, EXT_NONE);
+ int mem_idx = ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
+ tcg_gen_qemu_st_tl(data, addr, mem_idx, mop);
+ }
+ return true;
+#endif
+}
+
+static bool trans_hsv_b(DisasContext *ctx, arg_hsv_b *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hsv(ctx, a, MO_SB);
+}
+
+static bool trans_hsv_h(DisasContext *ctx, arg_hsv_h *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hsv(ctx, a, MO_TESW);
+}
+
+static bool trans_hsv_w(DisasContext *ctx, arg_hsv_w *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hsv(ctx, a, MO_TESL);
+}
+
+static bool trans_hlv_wu(DisasContext *ctx, arg_hlv_wu *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVH);
+ return do_hlv(ctx, a, MO_TEUL);
+}
+
+static bool trans_hlv_d(DisasContext *ctx, arg_hlv_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVH);
+ return do_hlv(ctx, a, MO_TEQ);
+}
+
+static bool trans_hsv_d(DisasContext *ctx, arg_hsv_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVH);
+ return do_hsv(ctx, a, MO_TEQ);
+}
+
+#ifndef CONFIG_USER_ONLY
+static bool do_hlvx(DisasContext *ctx, arg_r2 *a,
+ void (*func)(TCGv, TCGv_env, TCGv))
+{
+ if (check_access(ctx)) {
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ func(dest, cpu_env, addr);
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+ return true;
+}
+#endif
+
+static bool trans_hlvx_hu(DisasContext *ctx, arg_hlvx_hu *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+#ifndef CONFIG_USER_ONLY
+ return do_hlvx(ctx, a, gen_helper_hyp_hlvx_hu);
+#else
+ return false;
+#endif
+}
+
+static bool trans_hlvx_wu(DisasContext *ctx, arg_hlvx_wu *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+#ifndef CONFIG_USER_ONLY
+ return do_hlvx(ctx, a, gen_helper_hyp_hlvx_wu);
+#else
+ return false;
+#endif
+}
+
+static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+#ifndef CONFIG_USER_ONLY
+ gen_helper_hyp_gvma_tlb_flush(cpu_env);
+ return true;
+#endif
+ return false;
+}
+
+static bool trans_hfence_vvma(DisasContext *ctx, arg_sfence_vma *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+#ifndef CONFIG_USER_ONLY
+ gen_helper_hyp_tlb_flush(cpu_env);
+ return true;
+#endif
+ return false;
+}
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
new file mode 100644
index 000000000..e51dbc41c
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -0,0 +1,577 @@
+/*
+ * RISC-V translation routines for the RVXI Base Integer Instruction Set.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static bool trans_illegal(DisasContext *ctx, arg_empty *a)
+{
+ gen_exception_illegal(ctx);
+ return true;
+}
+
+static bool trans_c64_illegal(DisasContext *ctx, arg_empty *a)
+{
+ REQUIRE_64BIT(ctx);
+ return trans_illegal(ctx, a);
+}
+
+static bool trans_lui(DisasContext *ctx, arg_lui *a)
+{
+ if (a->rd != 0) {
+ tcg_gen_movi_tl(cpu_gpr[a->rd], a->imm);
+ }
+ return true;
+}
+
+static bool trans_auipc(DisasContext *ctx, arg_auipc *a)
+{
+ if (a->rd != 0) {
+ tcg_gen_movi_tl(cpu_gpr[a->rd], a->imm + ctx->base.pc_next);
+ }
+ return true;
+}
+
+static bool trans_jal(DisasContext *ctx, arg_jal *a)
+{
+ gen_jal(ctx, a->rd, a->imm);
+ return true;
+}
+
+static bool trans_jalr(DisasContext *ctx, arg_jalr *a)
+{
+ TCGLabel *misaligned = NULL;
+
+ tcg_gen_addi_tl(cpu_pc, get_gpr(ctx, a->rs1, EXT_NONE), a->imm);
+ tcg_gen_andi_tl(cpu_pc, cpu_pc, (target_ulong)-2);
+
+ if (!has_ext(ctx, RVC)) {
+ TCGv t0 = tcg_temp_new();
+
+ misaligned = gen_new_label();
+ tcg_gen_andi_tl(t0, cpu_pc, 0x2);
+ tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x0, misaligned);
+ tcg_temp_free(t0);
+ }
+
+ if (a->rd != 0) {
+ tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->pc_succ_insn);
+ }
+ tcg_gen_lookup_and_goto_ptr();
+
+ if (misaligned) {
+ gen_set_label(misaligned);
+ gen_exception_inst_addr_mis(ctx);
+ }
+ ctx->base.is_jmp = DISAS_NORETURN;
+
+ return true;
+}
+
+static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond)
+{
+ TCGLabel *l = gen_new_label();
+ TCGv src1 = get_gpr(ctx, a->rs1, EXT_SIGN);
+ TCGv src2 = get_gpr(ctx, a->rs2, EXT_SIGN);
+
+ tcg_gen_brcond_tl(cond, src1, src2, l);
+ gen_goto_tb(ctx, 1, ctx->pc_succ_insn);
+
+ gen_set_label(l); /* branch taken */
+
+ if (!has_ext(ctx, RVC) && ((ctx->base.pc_next + a->imm) & 0x3)) {
+ /* misaligned */
+ gen_exception_inst_addr_mis(ctx);
+ } else {
+ gen_goto_tb(ctx, 0, ctx->base.pc_next + a->imm);
+ }
+ ctx->base.is_jmp = DISAS_NORETURN;
+
+ return true;
+}
+
+static bool trans_beq(DisasContext *ctx, arg_beq *a)
+{
+ return gen_branch(ctx, a, TCG_COND_EQ);
+}
+
+static bool trans_bne(DisasContext *ctx, arg_bne *a)
+{
+ return gen_branch(ctx, a, TCG_COND_NE);
+}
+
+static bool trans_blt(DisasContext *ctx, arg_blt *a)
+{
+ return gen_branch(ctx, a, TCG_COND_LT);
+}
+
+static bool trans_bge(DisasContext *ctx, arg_bge *a)
+{
+ return gen_branch(ctx, a, TCG_COND_GE);
+}
+
+static bool trans_bltu(DisasContext *ctx, arg_bltu *a)
+{
+ return gen_branch(ctx, a, TCG_COND_LTU);
+}
+
+static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a)
+{
+ return gen_branch(ctx, a, TCG_COND_GEU);
+}
+
+static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop)
+{
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
+
+ if (a->imm) {
+ TCGv temp = temp_new(ctx);
+ tcg_gen_addi_tl(temp, addr, a->imm);
+ addr = temp;
+ }
+ addr = gen_pm_adjust_address(ctx, addr);
+
+ tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, memop);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_lb(DisasContext *ctx, arg_lb *a)
+{
+ return gen_load(ctx, a, MO_SB);
+}
+
+static bool trans_lh(DisasContext *ctx, arg_lh *a)
+{
+ return gen_load(ctx, a, MO_TESW);
+}
+
+static bool trans_lw(DisasContext *ctx, arg_lw *a)
+{
+ return gen_load(ctx, a, MO_TESL);
+}
+
+static bool trans_lbu(DisasContext *ctx, arg_lbu *a)
+{
+ return gen_load(ctx, a, MO_UB);
+}
+
+static bool trans_lhu(DisasContext *ctx, arg_lhu *a)
+{
+ return gen_load(ctx, a, MO_TEUW);
+}
+
+static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop)
+{
+ TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ TCGv data = get_gpr(ctx, a->rs2, EXT_NONE);
+
+ if (a->imm) {
+ TCGv temp = temp_new(ctx);
+ tcg_gen_addi_tl(temp, addr, a->imm);
+ addr = temp;
+ }
+ addr = gen_pm_adjust_address(ctx, addr);
+
+ tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop);
+ return true;
+}
+
+static bool trans_sb(DisasContext *ctx, arg_sb *a)
+{
+ return gen_store(ctx, a, MO_SB);
+}
+
+static bool trans_sh(DisasContext *ctx, arg_sh *a)
+{
+ return gen_store(ctx, a, MO_TESW);
+}
+
+static bool trans_sw(DisasContext *ctx, arg_sw *a)
+{
+ return gen_store(ctx, a, MO_TESL);
+}
+
+static bool trans_lwu(DisasContext *ctx, arg_lwu *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_load(ctx, a, MO_TEUL);
+}
+
+static bool trans_ld(DisasContext *ctx, arg_ld *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_load(ctx, a, MO_TEQ);
+}
+
+static bool trans_sd(DisasContext *ctx, arg_sd *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_store(ctx, a, MO_TEQ);
+}
+
+static bool trans_addi(DisasContext *ctx, arg_addi *a)
+{
+ return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_addi_tl);
+}
+
+static void gen_slt(TCGv ret, TCGv s1, TCGv s2)
+{
+ tcg_gen_setcond_tl(TCG_COND_LT, ret, s1, s2);
+}
+
+static void gen_sltu(TCGv ret, TCGv s1, TCGv s2)
+{
+ tcg_gen_setcond_tl(TCG_COND_LTU, ret, s1, s2);
+}
+
+static bool trans_slti(DisasContext *ctx, arg_slti *a)
+{
+ return gen_arith_imm_tl(ctx, a, EXT_SIGN, gen_slt);
+}
+
+static bool trans_sltiu(DisasContext *ctx, arg_sltiu *a)
+{
+ return gen_arith_imm_tl(ctx, a, EXT_SIGN, gen_sltu);
+}
+
+static bool trans_xori(DisasContext *ctx, arg_xori *a)
+{
+ return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_xori_tl);
+}
+
+static bool trans_ori(DisasContext *ctx, arg_ori *a)
+{
+ return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_ori_tl);
+}
+
+static bool trans_andi(DisasContext *ctx, arg_andi *a)
+{
+ return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_andi_tl);
+}
+
+static bool trans_slli(DisasContext *ctx, arg_slli *a)
+{
+ return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_shli_tl);
+}
+
+static void gen_srliw(TCGv dst, TCGv src, target_long shamt)
+{
+ tcg_gen_extract_tl(dst, src, shamt, 32 - shamt);
+}
+
+static bool trans_srli(DisasContext *ctx, arg_srli *a)
+{
+ return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE,
+ tcg_gen_shri_tl, gen_srliw);
+}
+
+static void gen_sraiw(TCGv dst, TCGv src, target_long shamt)
+{
+ tcg_gen_sextract_tl(dst, src, shamt, 32 - shamt);
+}
+
+static bool trans_srai(DisasContext *ctx, arg_srai *a)
+{
+ return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE,
+ tcg_gen_sari_tl, gen_sraiw);
+}
+
+static bool trans_add(DisasContext *ctx, arg_add *a)
+{
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_add_tl);
+}
+
+static bool trans_sub(DisasContext *ctx, arg_sub *a)
+{
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_sub_tl);
+}
+
+static bool trans_sll(DisasContext *ctx, arg_sll *a)
+{
+ return gen_shift(ctx, a, EXT_NONE, tcg_gen_shl_tl);
+}
+
+static bool trans_slt(DisasContext *ctx, arg_slt *a)
+{
+ return gen_arith(ctx, a, EXT_SIGN, gen_slt);
+}
+
+static bool trans_sltu(DisasContext *ctx, arg_sltu *a)
+{
+ return gen_arith(ctx, a, EXT_SIGN, gen_sltu);
+}
+
+static bool trans_xor(DisasContext *ctx, arg_xor *a)
+{
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_xor_tl);
+}
+
+static bool trans_srl(DisasContext *ctx, arg_srl *a)
+{
+ return gen_shift(ctx, a, EXT_ZERO, tcg_gen_shr_tl);
+}
+
+static bool trans_sra(DisasContext *ctx, arg_sra *a)
+{
+ return gen_shift(ctx, a, EXT_SIGN, tcg_gen_sar_tl);
+}
+
+static bool trans_or(DisasContext *ctx, arg_or *a)
+{
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_or_tl);
+}
+
+static bool trans_and(DisasContext *ctx, arg_and *a)
+{
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_and_tl);
+}
+
+static bool trans_addiw(DisasContext *ctx, arg_addiw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_addi_tl);
+}
+
+static bool trans_slliw(DisasContext *ctx, arg_slliw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_shli_tl);
+}
+
+static bool trans_srliw(DisasContext *ctx, arg_srliw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_srliw);
+}
+
+static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_sraiw);
+}
+
+static bool trans_addw(DisasContext *ctx, arg_addw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_add_tl);
+}
+
+static bool trans_subw(DisasContext *ctx, arg_subw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_sub_tl);
+}
+
+static bool trans_sllw(DisasContext *ctx, arg_sllw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift(ctx, a, EXT_NONE, tcg_gen_shl_tl);
+}
+
+static bool trans_srlw(DisasContext *ctx, arg_srlw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift(ctx, a, EXT_ZERO, tcg_gen_shr_tl);
+}
+
+static bool trans_sraw(DisasContext *ctx, arg_sraw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift(ctx, a, EXT_SIGN, tcg_gen_sar_tl);
+}
+
+static bool trans_fence(DisasContext *ctx, arg_fence *a)
+{
+ /* FENCE is a full memory barrier. */
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
+ return true;
+}
+
+static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
+{
+ if (!ctx->ext_ifencei) {
+ return false;
+ }
+
+ /*
+ * FENCE_I is a no-op in QEMU,
+ * however we need to end the translation block
+ */
+ tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
+ tcg_gen_exit_tb(NULL, 0);
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
+
+static bool do_csr_post(DisasContext *ctx)
+{
+ /* We may have changed important cpu state -- exit to main loop. */
+ tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
+ tcg_gen_exit_tb(NULL, 0);
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
+
+static bool do_csrr(DisasContext *ctx, int rd, int rc)
+{
+ TCGv dest = dest_gpr(ctx, rd);
+ TCGv_i32 csr = tcg_constant_i32(rc);
+
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ gen_helper_csrr(dest, cpu_env, csr);
+ gen_set_gpr(ctx, rd, dest);
+ return do_csr_post(ctx);
+}
+
+static bool do_csrw(DisasContext *ctx, int rc, TCGv src)
+{
+ TCGv_i32 csr = tcg_constant_i32(rc);
+
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ gen_helper_csrw(cpu_env, csr, src);
+ return do_csr_post(ctx);
+}
+
+static bool do_csrrw(DisasContext *ctx, int rd, int rc, TCGv src, TCGv mask)
+{
+ TCGv dest = dest_gpr(ctx, rd);
+ TCGv_i32 csr = tcg_constant_i32(rc);
+
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ gen_helper_csrrw(dest, cpu_env, csr, src, mask);
+ gen_set_gpr(ctx, rd, dest);
+ return do_csr_post(ctx);
+}
+
+static bool trans_csrrw(DisasContext *ctx, arg_csrrw *a)
+{
+ TCGv src = get_gpr(ctx, a->rs1, EXT_NONE);
+
+ /*
+ * If rd == 0, the insn shall not read the csr, nor cause any of the
+ * side effects that might occur on a csr read.
+ */
+ if (a->rd == 0) {
+ return do_csrw(ctx, a->csr, src);
+ }
+
+ TCGv mask = tcg_constant_tl(-1);
+ return do_csrrw(ctx, a->rd, a->csr, src, mask);
+}
+
+static bool trans_csrrs(DisasContext *ctx, arg_csrrs *a)
+{
+ /*
+ * If rs1 == 0, the insn shall not write to the csr at all, nor
+ * cause any of the side effects that might occur on a csr write.
+ * Note that if rs1 specifies a register other than x0, holding
+ * a zero value, the instruction will still attempt to write the
+ * unmodified value back to the csr and will cause side effects.
+ */
+ if (a->rs1 == 0) {
+ return do_csrr(ctx, a->rd, a->csr);
+ }
+
+ TCGv ones = tcg_constant_tl(-1);
+ TCGv mask = get_gpr(ctx, a->rs1, EXT_ZERO);
+ return do_csrrw(ctx, a->rd, a->csr, ones, mask);
+}
+
+static bool trans_csrrc(DisasContext *ctx, arg_csrrc *a)
+{
+ /*
+ * If rs1 == 0, the insn shall not write to the csr at all, nor
+ * cause any of the side effects that might occur on a csr write.
+ * Note that if rs1 specifies a register other than x0, holding
+ * a zero value, the instruction will still attempt to write the
+ * unmodified value back to the csr and will cause side effects.
+ */
+ if (a->rs1 == 0) {
+ return do_csrr(ctx, a->rd, a->csr);
+ }
+
+ TCGv mask = get_gpr(ctx, a->rs1, EXT_ZERO);
+ return do_csrrw(ctx, a->rd, a->csr, ctx->zero, mask);
+}
+
+static bool trans_csrrwi(DisasContext *ctx, arg_csrrwi *a)
+{
+ TCGv src = tcg_constant_tl(a->rs1);
+
+ /*
+ * If rd == 0, the insn shall not read the csr, nor cause any of the
+ * side effects that might occur on a csr read.
+ */
+ if (a->rd == 0) {
+ return do_csrw(ctx, a->csr, src);
+ }
+
+ TCGv mask = tcg_constant_tl(-1);
+ return do_csrrw(ctx, a->rd, a->csr, src, mask);
+}
+
+static bool trans_csrrsi(DisasContext *ctx, arg_csrrsi *a)
+{
+ /*
+ * If rs1 == 0, the insn shall not write to the csr at all, nor
+ * cause any of the side effects that might occur on a csr write.
+ * Note that if rs1 specifies a register other than x0, holding
+ * a zero value, the instruction will still attempt to write the
+ * unmodified value back to the csr and will cause side effects.
+ */
+ if (a->rs1 == 0) {
+ return do_csrr(ctx, a->rd, a->csr);
+ }
+
+ TCGv ones = tcg_constant_tl(-1);
+ TCGv mask = tcg_constant_tl(a->rs1);
+ return do_csrrw(ctx, a->rd, a->csr, ones, mask);
+}
+
+static bool trans_csrrci(DisasContext *ctx, arg_csrrci *a)
+{
+ /*
+ * If rs1 == 0, the insn shall not write to the csr at all, nor
+ * cause any of the side effects that might occur on a csr write.
+ * Note that if rs1 specifies a register other than x0, holding
+ * a zero value, the instruction will still attempt to write the
+ * unmodified value back to the csr and will cause side effects.
+ */
+ if (a->rs1 == 0) {
+ return do_csrr(ctx, a->rd, a->csr);
+ }
+
+ TCGv mask = tcg_constant_tl(a->rs1);
+ return do_csrrw(ctx, a->rd, a->csr, ctx->zero, mask);
+}
diff --git a/target/riscv/insn_trans/trans_rvm.c.inc b/target/riscv/insn_trans/trans_rvm.c.inc
new file mode 100644
index 000000000..2af0e5c13
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvm.c.inc
@@ -0,0 +1,271 @@
+/*
+ * RISC-V translation routines for the RV64M Standard Extension.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+static bool trans_mul(DisasContext *ctx, arg_mul *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl);
+}
+
+static void gen_mulh(TCGv ret, TCGv s1, TCGv s2)
+{
+ TCGv discard = tcg_temp_new();
+
+ tcg_gen_muls2_tl(discard, ret, s1, s2);
+ tcg_temp_free(discard);
+}
+
+static void gen_mulh_w(TCGv ret, TCGv s1, TCGv s2)
+{
+ tcg_gen_mul_tl(ret, s1, s2);
+ tcg_gen_sari_tl(ret, ret, 32);
+}
+
+static bool trans_mulh(DisasContext *ctx, arg_mulh *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith_per_ol(ctx, a, EXT_SIGN, gen_mulh, gen_mulh_w);
+}
+
+static void gen_mulhsu(TCGv ret, TCGv arg1, TCGv arg2)
+{
+ TCGv rl = tcg_temp_new();
+ TCGv rh = tcg_temp_new();
+
+ tcg_gen_mulu2_tl(rl, rh, arg1, arg2);
+ /* fix up for one negative */
+ tcg_gen_sari_tl(rl, arg1, TARGET_LONG_BITS - 1);
+ tcg_gen_and_tl(rl, rl, arg2);
+ tcg_gen_sub_tl(ret, rh, rl);
+
+ tcg_temp_free(rl);
+ tcg_temp_free(rh);
+}
+
+static void gen_mulhsu_w(TCGv ret, TCGv arg1, TCGv arg2)
+{
+ TCGv t1 = tcg_temp_new();
+ TCGv t2 = tcg_temp_new();
+
+ tcg_gen_ext32s_tl(t1, arg1);
+ tcg_gen_ext32u_tl(t2, arg2);
+ tcg_gen_mul_tl(ret, t1, t2);
+ tcg_temp_free(t1);
+ tcg_temp_free(t2);
+ tcg_gen_sari_tl(ret, ret, 32);
+}
+
+static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith_per_ol(ctx, a, EXT_NONE, gen_mulhsu, gen_mulhsu_w);
+}
+
+static void gen_mulhu(TCGv ret, TCGv s1, TCGv s2)
+{
+ TCGv discard = tcg_temp_new();
+
+ tcg_gen_mulu2_tl(discard, ret, s1, s2);
+ tcg_temp_free(discard);
+}
+
+static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ /* gen_mulh_w works for either sign as input. */
+ return gen_arith_per_ol(ctx, a, EXT_ZERO, gen_mulhu, gen_mulh_w);
+}
+
+static void gen_div(TCGv ret, TCGv source1, TCGv source2)
+{
+ TCGv temp1, temp2, zero, one, mone, min;
+
+ temp1 = tcg_temp_new();
+ temp2 = tcg_temp_new();
+ zero = tcg_constant_tl(0);
+ one = tcg_constant_tl(1);
+ mone = tcg_constant_tl(-1);
+ min = tcg_constant_tl(1ull << (TARGET_LONG_BITS - 1));
+
+ /*
+ * If overflow, set temp2 to 1, else source2.
+ * This produces the required result of min.
+ */
+ tcg_gen_setcond_tl(TCG_COND_EQ, temp1, source1, min);
+ tcg_gen_setcond_tl(TCG_COND_EQ, temp2, source2, mone);
+ tcg_gen_and_tl(temp1, temp1, temp2);
+ tcg_gen_movcond_tl(TCG_COND_NE, temp2, temp1, zero, one, source2);
+
+ /*
+ * If div by zero, set temp1 to -1 and temp2 to 1 to
+ * produce the required result of -1.
+ */
+ tcg_gen_movcond_tl(TCG_COND_EQ, temp1, source2, zero, mone, source1);
+ tcg_gen_movcond_tl(TCG_COND_EQ, temp2, source2, zero, one, temp2);
+
+ tcg_gen_div_tl(ret, temp1, temp2);
+
+ tcg_temp_free(temp1);
+ tcg_temp_free(temp2);
+}
+
+static bool trans_div(DisasContext *ctx, arg_div *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, EXT_SIGN, gen_div);
+}
+
+static void gen_divu(TCGv ret, TCGv source1, TCGv source2)
+{
+ TCGv temp1, temp2, zero, one, max;
+
+ temp1 = tcg_temp_new();
+ temp2 = tcg_temp_new();
+ zero = tcg_constant_tl(0);
+ one = tcg_constant_tl(1);
+ max = tcg_constant_tl(~0);
+
+ /*
+ * If div by zero, set temp1 to max and temp2 to 1 to
+ * produce the required result of max.
+ */
+ tcg_gen_movcond_tl(TCG_COND_EQ, temp1, source2, zero, max, source1);
+ tcg_gen_movcond_tl(TCG_COND_EQ, temp2, source2, zero, one, source2);
+ tcg_gen_divu_tl(ret, temp1, temp2);
+
+ tcg_temp_free(temp1);
+ tcg_temp_free(temp2);
+}
+
+static bool trans_divu(DisasContext *ctx, arg_divu *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, EXT_ZERO, gen_divu);
+}
+
+static void gen_rem(TCGv ret, TCGv source1, TCGv source2)
+{
+ TCGv temp1, temp2, zero, one, mone, min;
+
+ temp1 = tcg_temp_new();
+ temp2 = tcg_temp_new();
+ zero = tcg_constant_tl(0);
+ one = tcg_constant_tl(1);
+ mone = tcg_constant_tl(-1);
+ min = tcg_constant_tl(1ull << (TARGET_LONG_BITS - 1));
+
+ /*
+ * If overflow, set temp1 to 0, else source1.
+ * This avoids a possible host trap, and produces the required result of 0.
+ */
+ tcg_gen_setcond_tl(TCG_COND_EQ, temp1, source1, min);
+ tcg_gen_setcond_tl(TCG_COND_EQ, temp2, source2, mone);
+ tcg_gen_and_tl(temp1, temp1, temp2);
+ tcg_gen_movcond_tl(TCG_COND_NE, temp1, temp1, zero, zero, source1);
+
+ /*
+ * If div by zero, set temp2 to 1, else source2.
+ * This avoids a possible host trap, but produces an incorrect result.
+ */
+ tcg_gen_movcond_tl(TCG_COND_EQ, temp2, source2, zero, one, source2);
+
+ tcg_gen_rem_tl(temp1, temp1, temp2);
+
+ /* If div by zero, the required result is the original dividend. */
+ tcg_gen_movcond_tl(TCG_COND_EQ, ret, source2, zero, source1, temp1);
+
+ tcg_temp_free(temp1);
+ tcg_temp_free(temp2);
+}
+
+static bool trans_rem(DisasContext *ctx, arg_rem *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, EXT_SIGN, gen_rem);
+}
+
+static void gen_remu(TCGv ret, TCGv source1, TCGv source2)
+{
+ TCGv temp, zero, one;
+
+ temp = tcg_temp_new();
+ zero = tcg_constant_tl(0);
+ one = tcg_constant_tl(1);
+
+ /*
+ * If div by zero, set temp to 1, else source2.
+ * This avoids a possible host trap, but produces an incorrect result.
+ */
+ tcg_gen_movcond_tl(TCG_COND_EQ, temp, source2, zero, one, source2);
+
+ tcg_gen_remu_tl(temp, source1, temp);
+
+ /* If div by zero, the required result is the original dividend. */
+ tcg_gen_movcond_tl(TCG_COND_EQ, ret, source2, zero, source1, temp);
+
+ tcg_temp_free(temp);
+}
+
+static bool trans_remu(DisasContext *ctx, arg_remu *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, EXT_ZERO, gen_remu);
+}
+
+static bool trans_mulw(DisasContext *ctx, arg_mulw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVM);
+ ctx->ol = MXL_RV32;
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl);
+}
+
+static bool trans_divw(DisasContext *ctx, arg_divw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVM);
+ ctx->ol = MXL_RV32;
+ return gen_arith(ctx, a, EXT_SIGN, gen_div);
+}
+
+static bool trans_divuw(DisasContext *ctx, arg_divuw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVM);
+ ctx->ol = MXL_RV32;
+ return gen_arith(ctx, a, EXT_ZERO, gen_divu);
+}
+
+static bool trans_remw(DisasContext *ctx, arg_remw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVM);
+ ctx->ol = MXL_RV32;
+ return gen_arith(ctx, a, EXT_SIGN, gen_rem);
+}
+
+static bool trans_remuw(DisasContext *ctx, arg_remuw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVM);
+ ctx->ol = MXL_RV32;
+ return gen_arith(ctx, a, EXT_ZERO, gen_remu);
+}
diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc
new file mode 100644
index 000000000..17ee3babe
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvv.c.inc
@@ -0,0 +1,2867 @@
+/*
+ * RISC-V translation routines for the RVV Standard Extension.
+ *
+ * Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "tcg/tcg-op-gvec.h"
+#include "tcg/tcg-gvec-desc.h"
+#include "internals.h"
+
+static bool trans_vsetvl(DisasContext *ctx, arg_vsetvl *a)
+{
+ TCGv s1, s2, dst;
+
+ if (!has_ext(ctx, RVV)) {
+ return false;
+ }
+
+ s2 = get_gpr(ctx, a->rs2, EXT_ZERO);
+ dst = dest_gpr(ctx, a->rd);
+
+ /* Using x0 as the rs1 register specifier, encodes an infinite AVL */
+ if (a->rs1 == 0) {
+ /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */
+ s1 = tcg_constant_tl(RV_VLEN_MAX);
+ } else {
+ s1 = get_gpr(ctx, a->rs1, EXT_ZERO);
+ }
+ gen_helper_vsetvl(dst, cpu_env, s1, s2);
+ gen_set_gpr(ctx, a->rd, dst);
+
+ tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
+ tcg_gen_lookup_and_goto_ptr();
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
+
+static bool trans_vsetvli(DisasContext *ctx, arg_vsetvli *a)
+{
+ TCGv s1, s2, dst;
+
+ if (!has_ext(ctx, RVV)) {
+ return false;
+ }
+
+ s2 = tcg_constant_tl(a->zimm);
+ dst = dest_gpr(ctx, a->rd);
+
+ /* Using x0 as the rs1 register specifier, encodes an infinite AVL */
+ if (a->rs1 == 0) {
+ /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */
+ s1 = tcg_constant_tl(RV_VLEN_MAX);
+ } else {
+ s1 = get_gpr(ctx, a->rs1, EXT_ZERO);
+ }
+ gen_helper_vsetvl(dst, cpu_env, s1, s2);
+ gen_set_gpr(ctx, a->rd, dst);
+
+ gen_goto_tb(ctx, 0, ctx->pc_succ_insn);
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
+
+/* vector register offset from env */
+static uint32_t vreg_ofs(DisasContext *s, int reg)
+{
+ return offsetof(CPURISCVState, vreg) + reg * s->vlen / 8;
+}
+
+/* check functions */
+
+/*
+ * In cpu_get_tb_cpu_state(), set VILL if RVV was not present.
+ * So RVV is also be checked in this function.
+ */
+static bool vext_check_isa_ill(DisasContext *s)
+{
+ return !s->vill;
+}
+
+/*
+ * There are two rules check here.
+ *
+ * 1. Vector register numbers are multiples of LMUL. (Section 3.2)
+ *
+ * 2. For all widening instructions, the destination LMUL value must also be
+ * a supported LMUL value. (Section 11.2)
+ */
+static bool vext_check_reg(DisasContext *s, uint32_t reg, bool widen)
+{
+ /*
+ * The destination vector register group results are arranged as if both
+ * SEW and LMUL were at twice their current settings. (Section 11.2).
+ */
+ int legal = widen ? 2 << s->lmul : 1 << s->lmul;
+
+ return !((s->lmul == 0x3 && widen) || (reg % legal));
+}
+
+/*
+ * There are two rules check here.
+ *
+ * 1. The destination vector register group for a masked vector instruction can
+ * only overlap the source mask register (v0) when LMUL=1. (Section 5.3)
+ *
+ * 2. In widen instructions and some other insturctions, like vslideup.vx,
+ * there is no need to check whether LMUL=1.
+ */
+static bool vext_check_overlap_mask(DisasContext *s, uint32_t vd, bool vm,
+ bool force)
+{
+ return (vm != 0 || vd != 0) || (!force && (s->lmul == 0));
+}
+
+/* The LMUL setting must be such that LMUL * NFIELDS <= 8. (Section 7.8) */
+static bool vext_check_nf(DisasContext *s, uint32_t nf)
+{
+ return (1 << s->lmul) * nf <= 8;
+}
+
+/*
+ * The destination vector register group cannot overlap a source vector register
+ * group of a different element width. (Section 11.2)
+ */
+static inline bool vext_check_overlap_group(int rd, int dlen, int rs, int slen)
+{
+ return ((rd >= rs + slen) || (rs >= rd + dlen));
+}
+/* common translation macro */
+#define GEN_VEXT_TRANS(NAME, SEQ, ARGTYPE, OP, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_##ARGTYPE *a)\
+{ \
+ if (CHECK(s, a)) { \
+ return OP(s, a, SEQ); \
+ } \
+ return false; \
+}
+
+/*
+ *** unit stride load and store
+ */
+typedef void gen_helper_ldst_us(TCGv_ptr, TCGv_ptr, TCGv,
+ TCGv_env, TCGv_i32);
+
+static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data,
+ gen_helper_ldst_us *fn, DisasContext *s)
+{
+ TCGv_ptr dest, mask;
+ TCGv base;
+ TCGv_i32 desc;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ base = get_gpr(s, rs1, EXT_NONE);
+
+ /*
+ * As simd_desc supports at most 256 bytes, and in this implementation,
+ * the max vector group length is 2048 bytes. So split it into two parts.
+ *
+ * The first part is vlen in bytes, encoded in maxsz of simd_desc.
+ * The second part is lmul, encoded in data of simd_desc.
+ */
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, base, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ gen_set_label(over);
+ return true;
+}
+
+static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_ldst_us *fn;
+ static gen_helper_ldst_us * const fns[2][7][4] = {
+ /* masked unit stride load */
+ { { gen_helper_vlb_v_b_mask, gen_helper_vlb_v_h_mask,
+ gen_helper_vlb_v_w_mask, gen_helper_vlb_v_d_mask },
+ { NULL, gen_helper_vlh_v_h_mask,
+ gen_helper_vlh_v_w_mask, gen_helper_vlh_v_d_mask },
+ { NULL, NULL,
+ gen_helper_vlw_v_w_mask, gen_helper_vlw_v_d_mask },
+ { gen_helper_vle_v_b_mask, gen_helper_vle_v_h_mask,
+ gen_helper_vle_v_w_mask, gen_helper_vle_v_d_mask },
+ { gen_helper_vlbu_v_b_mask, gen_helper_vlbu_v_h_mask,
+ gen_helper_vlbu_v_w_mask, gen_helper_vlbu_v_d_mask },
+ { NULL, gen_helper_vlhu_v_h_mask,
+ gen_helper_vlhu_v_w_mask, gen_helper_vlhu_v_d_mask },
+ { NULL, NULL,
+ gen_helper_vlwu_v_w_mask, gen_helper_vlwu_v_d_mask } },
+ /* unmasked unit stride load */
+ { { gen_helper_vlb_v_b, gen_helper_vlb_v_h,
+ gen_helper_vlb_v_w, gen_helper_vlb_v_d },
+ { NULL, gen_helper_vlh_v_h,
+ gen_helper_vlh_v_w, gen_helper_vlh_v_d },
+ { NULL, NULL,
+ gen_helper_vlw_v_w, gen_helper_vlw_v_d },
+ { gen_helper_vle_v_b, gen_helper_vle_v_h,
+ gen_helper_vle_v_w, gen_helper_vle_v_d },
+ { gen_helper_vlbu_v_b, gen_helper_vlbu_v_h,
+ gen_helper_vlbu_v_w, gen_helper_vlbu_v_d },
+ { NULL, gen_helper_vlhu_v_h,
+ gen_helper_vlhu_v_w, gen_helper_vlhu_v_d },
+ { NULL, NULL,
+ gen_helper_vlwu_v_w, gen_helper_vlwu_v_d } }
+ };
+
+ fn = fns[a->vm][seq][s->sew];
+ if (fn == NULL) {
+ return false;
+ }
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, NF, a->nf);
+ return ldst_us_trans(a->rd, a->rs1, data, fn, s);
+}
+
+static bool ld_us_check(DisasContext *s, arg_r2nfvm* a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_nf(s, a->nf));
+}
+
+GEN_VEXT_TRANS(vlb_v, 0, r2nfvm, ld_us_op, ld_us_check)
+GEN_VEXT_TRANS(vlh_v, 1, r2nfvm, ld_us_op, ld_us_check)
+GEN_VEXT_TRANS(vlw_v, 2, r2nfvm, ld_us_op, ld_us_check)
+GEN_VEXT_TRANS(vle_v, 3, r2nfvm, ld_us_op, ld_us_check)
+GEN_VEXT_TRANS(vlbu_v, 4, r2nfvm, ld_us_op, ld_us_check)
+GEN_VEXT_TRANS(vlhu_v, 5, r2nfvm, ld_us_op, ld_us_check)
+GEN_VEXT_TRANS(vlwu_v, 6, r2nfvm, ld_us_op, ld_us_check)
+
+static bool st_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_ldst_us *fn;
+ static gen_helper_ldst_us * const fns[2][4][4] = {
+ /* masked unit stride load and store */
+ { { gen_helper_vsb_v_b_mask, gen_helper_vsb_v_h_mask,
+ gen_helper_vsb_v_w_mask, gen_helper_vsb_v_d_mask },
+ { NULL, gen_helper_vsh_v_h_mask,
+ gen_helper_vsh_v_w_mask, gen_helper_vsh_v_d_mask },
+ { NULL, NULL,
+ gen_helper_vsw_v_w_mask, gen_helper_vsw_v_d_mask },
+ { gen_helper_vse_v_b_mask, gen_helper_vse_v_h_mask,
+ gen_helper_vse_v_w_mask, gen_helper_vse_v_d_mask } },
+ /* unmasked unit stride store */
+ { { gen_helper_vsb_v_b, gen_helper_vsb_v_h,
+ gen_helper_vsb_v_w, gen_helper_vsb_v_d },
+ { NULL, gen_helper_vsh_v_h,
+ gen_helper_vsh_v_w, gen_helper_vsh_v_d },
+ { NULL, NULL,
+ gen_helper_vsw_v_w, gen_helper_vsw_v_d },
+ { gen_helper_vse_v_b, gen_helper_vse_v_h,
+ gen_helper_vse_v_w, gen_helper_vse_v_d } }
+ };
+
+ fn = fns[a->vm][seq][s->sew];
+ if (fn == NULL) {
+ return false;
+ }
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, NF, a->nf);
+ return ldst_us_trans(a->rd, a->rs1, data, fn, s);
+}
+
+static bool st_us_check(DisasContext *s, arg_r2nfvm* a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_nf(s, a->nf));
+}
+
+GEN_VEXT_TRANS(vsb_v, 0, r2nfvm, st_us_op, st_us_check)
+GEN_VEXT_TRANS(vsh_v, 1, r2nfvm, st_us_op, st_us_check)
+GEN_VEXT_TRANS(vsw_v, 2, r2nfvm, st_us_op, st_us_check)
+GEN_VEXT_TRANS(vse_v, 3, r2nfvm, st_us_op, st_us_check)
+
+/*
+ *** stride load and store
+ */
+typedef void gen_helper_ldst_stride(TCGv_ptr, TCGv_ptr, TCGv,
+ TCGv, TCGv_env, TCGv_i32);
+
+static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2,
+ uint32_t data, gen_helper_ldst_stride *fn,
+ DisasContext *s)
+{
+ TCGv_ptr dest, mask;
+ TCGv base, stride;
+ TCGv_i32 desc;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ base = get_gpr(s, rs1, EXT_NONE);
+ stride = get_gpr(s, rs2, EXT_NONE);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, base, stride, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ gen_set_label(over);
+ return true;
+}
+
+static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_ldst_stride *fn;
+ static gen_helper_ldst_stride * const fns[7][4] = {
+ { gen_helper_vlsb_v_b, gen_helper_vlsb_v_h,
+ gen_helper_vlsb_v_w, gen_helper_vlsb_v_d },
+ { NULL, gen_helper_vlsh_v_h,
+ gen_helper_vlsh_v_w, gen_helper_vlsh_v_d },
+ { NULL, NULL,
+ gen_helper_vlsw_v_w, gen_helper_vlsw_v_d },
+ { gen_helper_vlse_v_b, gen_helper_vlse_v_h,
+ gen_helper_vlse_v_w, gen_helper_vlse_v_d },
+ { gen_helper_vlsbu_v_b, gen_helper_vlsbu_v_h,
+ gen_helper_vlsbu_v_w, gen_helper_vlsbu_v_d },
+ { NULL, gen_helper_vlshu_v_h,
+ gen_helper_vlshu_v_w, gen_helper_vlshu_v_d },
+ { NULL, NULL,
+ gen_helper_vlswu_v_w, gen_helper_vlswu_v_d },
+ };
+
+ fn = fns[seq][s->sew];
+ if (fn == NULL) {
+ return false;
+ }
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, NF, a->nf);
+ return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s);
+}
+
+static bool ld_stride_check(DisasContext *s, arg_rnfvm* a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_nf(s, a->nf));
+}
+
+GEN_VEXT_TRANS(vlsb_v, 0, rnfvm, ld_stride_op, ld_stride_check)
+GEN_VEXT_TRANS(vlsh_v, 1, rnfvm, ld_stride_op, ld_stride_check)
+GEN_VEXT_TRANS(vlsw_v, 2, rnfvm, ld_stride_op, ld_stride_check)
+GEN_VEXT_TRANS(vlse_v, 3, rnfvm, ld_stride_op, ld_stride_check)
+GEN_VEXT_TRANS(vlsbu_v, 4, rnfvm, ld_stride_op, ld_stride_check)
+GEN_VEXT_TRANS(vlshu_v, 5, rnfvm, ld_stride_op, ld_stride_check)
+GEN_VEXT_TRANS(vlswu_v, 6, rnfvm, ld_stride_op, ld_stride_check)
+
+static bool st_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_ldst_stride *fn;
+ static gen_helper_ldst_stride * const fns[4][4] = {
+ /* masked stride store */
+ { gen_helper_vssb_v_b, gen_helper_vssb_v_h,
+ gen_helper_vssb_v_w, gen_helper_vssb_v_d },
+ { NULL, gen_helper_vssh_v_h,
+ gen_helper_vssh_v_w, gen_helper_vssh_v_d },
+ { NULL, NULL,
+ gen_helper_vssw_v_w, gen_helper_vssw_v_d },
+ { gen_helper_vsse_v_b, gen_helper_vsse_v_h,
+ gen_helper_vsse_v_w, gen_helper_vsse_v_d }
+ };
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, NF, a->nf);
+ fn = fns[seq][s->sew];
+ if (fn == NULL) {
+ return false;
+ }
+
+ return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s);
+}
+
+static bool st_stride_check(DisasContext *s, arg_rnfvm* a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_nf(s, a->nf));
+}
+
+GEN_VEXT_TRANS(vssb_v, 0, rnfvm, st_stride_op, st_stride_check)
+GEN_VEXT_TRANS(vssh_v, 1, rnfvm, st_stride_op, st_stride_check)
+GEN_VEXT_TRANS(vssw_v, 2, rnfvm, st_stride_op, st_stride_check)
+GEN_VEXT_TRANS(vsse_v, 3, rnfvm, st_stride_op, st_stride_check)
+
+/*
+ *** index load and store
+ */
+typedef void gen_helper_ldst_index(TCGv_ptr, TCGv_ptr, TCGv,
+ TCGv_ptr, TCGv_env, TCGv_i32);
+
+static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
+ uint32_t data, gen_helper_ldst_index *fn,
+ DisasContext *s)
+{
+ TCGv_ptr dest, mask, index;
+ TCGv base;
+ TCGv_i32 desc;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ index = tcg_temp_new_ptr();
+ base = get_gpr(s, rs1, EXT_NONE);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, base, index, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(index);
+ gen_set_label(over);
+ return true;
+}
+
+static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_ldst_index *fn;
+ static gen_helper_ldst_index * const fns[7][4] = {
+ { gen_helper_vlxb_v_b, gen_helper_vlxb_v_h,
+ gen_helper_vlxb_v_w, gen_helper_vlxb_v_d },
+ { NULL, gen_helper_vlxh_v_h,
+ gen_helper_vlxh_v_w, gen_helper_vlxh_v_d },
+ { NULL, NULL,
+ gen_helper_vlxw_v_w, gen_helper_vlxw_v_d },
+ { gen_helper_vlxe_v_b, gen_helper_vlxe_v_h,
+ gen_helper_vlxe_v_w, gen_helper_vlxe_v_d },
+ { gen_helper_vlxbu_v_b, gen_helper_vlxbu_v_h,
+ gen_helper_vlxbu_v_w, gen_helper_vlxbu_v_d },
+ { NULL, gen_helper_vlxhu_v_h,
+ gen_helper_vlxhu_v_w, gen_helper_vlxhu_v_d },
+ { NULL, NULL,
+ gen_helper_vlxwu_v_w, gen_helper_vlxwu_v_d },
+ };
+
+ fn = fns[seq][s->sew];
+ if (fn == NULL) {
+ return false;
+ }
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, NF, a->nf);
+ return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s);
+}
+
+/*
+ * For vector indexed segment loads, the destination vector register
+ * groups cannot overlap the source vector register group (specified by
+ * `vs2`), else an illegal instruction exception is raised.
+ */
+static bool ld_index_check(DisasContext *s, arg_rnfvm* a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_nf(s, a->nf) &&
+ ((a->nf == 1) ||
+ vext_check_overlap_group(a->rd, a->nf << s->lmul,
+ a->rs2, 1 << s->lmul)));
+}
+
+GEN_VEXT_TRANS(vlxb_v, 0, rnfvm, ld_index_op, ld_index_check)
+GEN_VEXT_TRANS(vlxh_v, 1, rnfvm, ld_index_op, ld_index_check)
+GEN_VEXT_TRANS(vlxw_v, 2, rnfvm, ld_index_op, ld_index_check)
+GEN_VEXT_TRANS(vlxe_v, 3, rnfvm, ld_index_op, ld_index_check)
+GEN_VEXT_TRANS(vlxbu_v, 4, rnfvm, ld_index_op, ld_index_check)
+GEN_VEXT_TRANS(vlxhu_v, 5, rnfvm, ld_index_op, ld_index_check)
+GEN_VEXT_TRANS(vlxwu_v, 6, rnfvm, ld_index_op, ld_index_check)
+
+static bool st_index_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_ldst_index *fn;
+ static gen_helper_ldst_index * const fns[4][4] = {
+ { gen_helper_vsxb_v_b, gen_helper_vsxb_v_h,
+ gen_helper_vsxb_v_w, gen_helper_vsxb_v_d },
+ { NULL, gen_helper_vsxh_v_h,
+ gen_helper_vsxh_v_w, gen_helper_vsxh_v_d },
+ { NULL, NULL,
+ gen_helper_vsxw_v_w, gen_helper_vsxw_v_d },
+ { gen_helper_vsxe_v_b, gen_helper_vsxe_v_h,
+ gen_helper_vsxe_v_w, gen_helper_vsxe_v_d }
+ };
+
+ fn = fns[seq][s->sew];
+ if (fn == NULL) {
+ return false;
+ }
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, NF, a->nf);
+ return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s);
+}
+
+static bool st_index_check(DisasContext *s, arg_rnfvm* a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_nf(s, a->nf));
+}
+
+GEN_VEXT_TRANS(vsxb_v, 0, rnfvm, st_index_op, st_index_check)
+GEN_VEXT_TRANS(vsxh_v, 1, rnfvm, st_index_op, st_index_check)
+GEN_VEXT_TRANS(vsxw_v, 2, rnfvm, st_index_op, st_index_check)
+GEN_VEXT_TRANS(vsxe_v, 3, rnfvm, st_index_op, st_index_check)
+
+/*
+ *** unit stride fault-only-first load
+ */
+static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data,
+ gen_helper_ldst_us *fn, DisasContext *s)
+{
+ TCGv_ptr dest, mask;
+ TCGv base;
+ TCGv_i32 desc;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ base = get_gpr(s, rs1, EXT_NONE);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, base, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ gen_set_label(over);
+ return true;
+}
+
+static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_ldst_us *fn;
+ static gen_helper_ldst_us * const fns[7][4] = {
+ { gen_helper_vlbff_v_b, gen_helper_vlbff_v_h,
+ gen_helper_vlbff_v_w, gen_helper_vlbff_v_d },
+ { NULL, gen_helper_vlhff_v_h,
+ gen_helper_vlhff_v_w, gen_helper_vlhff_v_d },
+ { NULL, NULL,
+ gen_helper_vlwff_v_w, gen_helper_vlwff_v_d },
+ { gen_helper_vleff_v_b, gen_helper_vleff_v_h,
+ gen_helper_vleff_v_w, gen_helper_vleff_v_d },
+ { gen_helper_vlbuff_v_b, gen_helper_vlbuff_v_h,
+ gen_helper_vlbuff_v_w, gen_helper_vlbuff_v_d },
+ { NULL, gen_helper_vlhuff_v_h,
+ gen_helper_vlhuff_v_w, gen_helper_vlhuff_v_d },
+ { NULL, NULL,
+ gen_helper_vlwuff_v_w, gen_helper_vlwuff_v_d }
+ };
+
+ fn = fns[seq][s->sew];
+ if (fn == NULL) {
+ return false;
+ }
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, NF, a->nf);
+ return ldff_trans(a->rd, a->rs1, data, fn, s);
+}
+
+GEN_VEXT_TRANS(vlbff_v, 0, r2nfvm, ldff_op, ld_us_check)
+GEN_VEXT_TRANS(vlhff_v, 1, r2nfvm, ldff_op, ld_us_check)
+GEN_VEXT_TRANS(vlwff_v, 2, r2nfvm, ldff_op, ld_us_check)
+GEN_VEXT_TRANS(vleff_v, 3, r2nfvm, ldff_op, ld_us_check)
+GEN_VEXT_TRANS(vlbuff_v, 4, r2nfvm, ldff_op, ld_us_check)
+GEN_VEXT_TRANS(vlhuff_v, 5, r2nfvm, ldff_op, ld_us_check)
+GEN_VEXT_TRANS(vlwuff_v, 6, r2nfvm, ldff_op, ld_us_check)
+
+/*
+ *** vector atomic operation
+ */
+typedef void gen_helper_amo(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr,
+ TCGv_env, TCGv_i32);
+
+static bool amo_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
+ uint32_t data, gen_helper_amo *fn, DisasContext *s)
+{
+ TCGv_ptr dest, mask, index;
+ TCGv base;
+ TCGv_i32 desc;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ index = tcg_temp_new_ptr();
+ base = get_gpr(s, rs1, EXT_NONE);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, base, index, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(index);
+ gen_set_label(over);
+ return true;
+}
+
+static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_amo *fn;
+ static gen_helper_amo *const fnsw[9] = {
+ /* no atomic operation */
+ gen_helper_vamoswapw_v_w,
+ gen_helper_vamoaddw_v_w,
+ gen_helper_vamoxorw_v_w,
+ gen_helper_vamoandw_v_w,
+ gen_helper_vamoorw_v_w,
+ gen_helper_vamominw_v_w,
+ gen_helper_vamomaxw_v_w,
+ gen_helper_vamominuw_v_w,
+ gen_helper_vamomaxuw_v_w
+ };
+ static gen_helper_amo *const fnsd[18] = {
+ gen_helper_vamoswapw_v_d,
+ gen_helper_vamoaddw_v_d,
+ gen_helper_vamoxorw_v_d,
+ gen_helper_vamoandw_v_d,
+ gen_helper_vamoorw_v_d,
+ gen_helper_vamominw_v_d,
+ gen_helper_vamomaxw_v_d,
+ gen_helper_vamominuw_v_d,
+ gen_helper_vamomaxuw_v_d,
+ gen_helper_vamoswapd_v_d,
+ gen_helper_vamoaddd_v_d,
+ gen_helper_vamoxord_v_d,
+ gen_helper_vamoandd_v_d,
+ gen_helper_vamoord_v_d,
+ gen_helper_vamomind_v_d,
+ gen_helper_vamomaxd_v_d,
+ gen_helper_vamominud_v_d,
+ gen_helper_vamomaxud_v_d
+ };
+
+ if (tb_cflags(s->base.tb) & CF_PARALLEL) {
+ gen_helper_exit_atomic(cpu_env);
+ s->base.is_jmp = DISAS_NORETURN;
+ return true;
+ }
+
+ switch (s->sew) {
+ case 0 ... 2:
+ assert(seq < ARRAY_SIZE(fnsw));
+ fn = fnsw[seq];
+ break;
+ case 3:
+ /* XLEN check done in amo_check(). */
+ assert(seq < ARRAY_SIZE(fnsd));
+ fn = fnsd[seq];
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, WD, a->wd);
+ return amo_trans(a->rd, a->rs1, a->rs2, data, fn, s);
+}
+/*
+ * There are two rules check here.
+ *
+ * 1. SEW must be at least as wide as the AMO memory element size.
+ *
+ * 2. If SEW is greater than XLEN, an illegal instruction exception is raised.
+ */
+static bool amo_check(DisasContext *s, arg_rwdvm* a)
+{
+ return (!s->vill && has_ext(s, RVA) &&
+ (!a->wd || vext_check_overlap_mask(s, a->rd, a->vm, false)) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ ((1 << s->sew) <= sizeof(target_ulong)) &&
+ ((1 << s->sew) >= 4));
+}
+
+static bool amo_check64(DisasContext *s, arg_rwdvm* a)
+{
+ REQUIRE_64BIT(s);
+ return amo_check(s, a);
+}
+
+GEN_VEXT_TRANS(vamoswapw_v, 0, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamoaddw_v, 1, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamoxorw_v, 2, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamoandw_v, 3, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamoorw_v, 4, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamominw_v, 5, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamomaxw_v, 6, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamominuw_v, 7, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamomaxuw_v, 8, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamoswapd_v, 9, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamoaddd_v, 10, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamoxord_v, 11, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamoandd_v, 12, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamoord_v, 13, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamomind_v, 14, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamomaxd_v, 15, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamominud_v, 16, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamomaxud_v, 17, rwdvm, amo_op, amo_check64)
+
+/*
+ *** Vector Integer Arithmetic Instructions
+ */
+#define MAXSZ(s) (s->vlen >> (3 - s->lmul))
+
+static bool opivv_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false));
+}
+
+typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t,
+ uint32_t, uint32_t, uint32_t);
+
+static inline bool
+do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn,
+ gen_helper_gvec_4_ptr *fn)
+{
+ TCGLabel *over = gen_new_label();
+ if (!opivv_check(s, a)) {
+ return false;
+ }
+
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ if (a->vm && s->vl_eq_vlmax) {
+ gvec_fn(s->sew, vreg_ofs(s, a->rd),
+ vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1),
+ MAXSZ(s), MAXSZ(s));
+ } else {
+ uint32_t data = 0;
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
+ vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
+ cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
+ }
+ gen_set_label(over);
+ return true;
+}
+
+/* OPIVV with GVEC IR */
+#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_gvec_4_ptr * const fns[4] = { \
+ gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
+ }; \
+ return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
+}
+
+GEN_OPIVV_GVEC_TRANS(vadd_vv, add)
+GEN_OPIVV_GVEC_TRANS(vsub_vv, sub)
+
+typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr,
+ TCGv_env, TCGv_i32);
+
+static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
+ gen_helper_opivx *fn, DisasContext *s)
+{
+ TCGv_ptr dest, src2, mask;
+ TCGv src1;
+ TCGv_i32 desc;
+ uint32_t data = 0;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ src2 = tcg_temp_new_ptr();
+ src1 = get_gpr(s, rs1, EXT_NONE);
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, src1, src2, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(src2);
+ gen_set_label(over);
+ return true;
+}
+
+static bool opivx_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false));
+}
+
+typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64,
+ uint32_t, uint32_t);
+
+static inline bool
+do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn,
+ gen_helper_opivx *fn)
+{
+ if (!opivx_check(s, a)) {
+ return false;
+ }
+
+ if (a->vm && s->vl_eq_vlmax) {
+ TCGv_i64 src1 = tcg_temp_new_i64();
+
+ tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN));
+ gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
+ src1, MAXSZ(s), MAXSZ(s));
+
+ tcg_temp_free_i64(src1);
+ return true;
+ }
+ return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
+}
+
+/* OPIVX with GVEC IR */
+#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_opivx * const fns[4] = { \
+ gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
+ }; \
+ return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
+}
+
+GEN_OPIVX_GVEC_TRANS(vadd_vx, adds)
+GEN_OPIVX_GVEC_TRANS(vsub_vx, subs)
+
+static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
+{
+ tcg_gen_vec_sub8_i64(d, b, a);
+}
+
+static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
+{
+ tcg_gen_vec_sub16_i64(d, b, a);
+}
+
+static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ tcg_gen_sub_i32(ret, arg2, arg1);
+}
+
+static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_sub_i64(ret, arg2, arg1);
+}
+
+static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
+{
+ tcg_gen_sub_vec(vece, r, b, a);
+}
+
+static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs,
+ TCGv_i64 c, uint32_t oprsz, uint32_t maxsz)
+{
+ static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 };
+ static const GVecGen2s rsub_op[4] = {
+ { .fni8 = gen_vec_rsub8_i64,
+ .fniv = gen_rsub_vec,
+ .fno = gen_helper_vec_rsubs8,
+ .opt_opc = vecop_list,
+ .vece = MO_8 },
+ { .fni8 = gen_vec_rsub16_i64,
+ .fniv = gen_rsub_vec,
+ .fno = gen_helper_vec_rsubs16,
+ .opt_opc = vecop_list,
+ .vece = MO_16 },
+ { .fni4 = gen_rsub_i32,
+ .fniv = gen_rsub_vec,
+ .fno = gen_helper_vec_rsubs32,
+ .opt_opc = vecop_list,
+ .vece = MO_32 },
+ { .fni8 = gen_rsub_i64,
+ .fniv = gen_rsub_vec,
+ .fno = gen_helper_vec_rsubs64,
+ .opt_opc = vecop_list,
+ .prefer_i64 = TCG_TARGET_REG_BITS == 64,
+ .vece = MO_64 },
+ };
+
+ tcg_debug_assert(vece <= MO_64);
+ tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]);
+}
+
+GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs)
+
+static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm,
+ gen_helper_opivx *fn, DisasContext *s, int zx)
+{
+ TCGv_ptr dest, src2, mask;
+ TCGv src1;
+ TCGv_i32 desc;
+ uint32_t data = 0;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ src2 = tcg_temp_new_ptr();
+ if (zx) {
+ src1 = tcg_constant_tl(imm);
+ } else {
+ src1 = tcg_constant_tl(sextract64(imm, 0, 5));
+ }
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, src1, src2, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(src2);
+ gen_set_label(over);
+ return true;
+}
+
+typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t,
+ uint32_t, uint32_t);
+
+static inline bool
+do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn,
+ gen_helper_opivx *fn, int zx)
+{
+ if (!opivx_check(s, a)) {
+ return false;
+ }
+
+ if (a->vm && s->vl_eq_vlmax) {
+ if (zx) {
+ gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
+ extract64(a->rs1, 0, 5), MAXSZ(s), MAXSZ(s));
+ } else {
+ gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
+ sextract64(a->rs1, 0, 5), MAXSZ(s), MAXSZ(s));
+ }
+ } else {
+ return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, zx);
+ }
+ return true;
+}
+
+/* OPIVI with GVEC IR */
+#define GEN_OPIVI_GVEC_TRANS(NAME, ZX, OPIVX, SUF) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_opivx * const fns[4] = { \
+ gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \
+ gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \
+ }; \
+ return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF, \
+ fns[s->sew], ZX); \
+}
+
+GEN_OPIVI_GVEC_TRANS(vadd_vi, 0, vadd_vx, addi)
+
+static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs,
+ int64_t c, uint32_t oprsz, uint32_t maxsz)
+{
+ TCGv_i64 tmp = tcg_constant_i64(c);
+ tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz);
+}
+
+GEN_OPIVI_GVEC_TRANS(vrsub_vi, 0, vrsub_vx, rsubi)
+
+/* Vector Widening Integer Add/Subtract */
+
+/* OPIVV with WIDEN */
+static bool opivv_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
+ 1 << s->lmul) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
+ 1 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3));
+}
+
+static bool do_opivv_widen(DisasContext *s, arg_rmrr *a,
+ gen_helper_gvec_4_ptr *fn,
+ bool (*checkfn)(DisasContext *, arg_rmrr *))
+{
+ if (checkfn(s, a)) {
+ uint32_t data = 0;
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
+ vreg_ofs(s, a->rs1),
+ vreg_ofs(s, a->rs2),
+ cpu_env, s->vlen / 8, s->vlen / 8,
+ data, fn);
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
+
+#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_gvec_4_ptr * const fns[3] = { \
+ gen_helper_##NAME##_b, \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w \
+ }; \
+ return do_opivv_widen(s, a, fns[s->sew], CHECK); \
+}
+
+GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check)
+
+/* OPIVX with WIDEN */
+static bool opivx_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
+ 1 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3));
+}
+
+static bool do_opivx_widen(DisasContext *s, arg_rmrr *a,
+ gen_helper_opivx *fn)
+{
+ if (opivx_widen_check(s, a)) {
+ return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
+ }
+ return false;
+}
+
+#define GEN_OPIVX_WIDEN_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_opivx * const fns[3] = { \
+ gen_helper_##NAME##_b, \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w \
+ }; \
+ return do_opivx_widen(s, a, fns[s->sew]); \
+}
+
+GEN_OPIVX_WIDEN_TRANS(vwaddu_vx)
+GEN_OPIVX_WIDEN_TRANS(vwadd_vx)
+GEN_OPIVX_WIDEN_TRANS(vwsubu_vx)
+GEN_OPIVX_WIDEN_TRANS(vwsub_vx)
+
+/* WIDEN OPIVV with WIDEN */
+static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, true) &&
+ vext_check_reg(s, a->rs1, false) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
+ 1 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3));
+}
+
+static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a,
+ gen_helper_gvec_4_ptr *fn)
+{
+ if (opiwv_widen_check(s, a)) {
+ uint32_t data = 0;
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
+ vreg_ofs(s, a->rs1),
+ vreg_ofs(s, a->rs2),
+ cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
+
+#define GEN_OPIWV_WIDEN_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_gvec_4_ptr * const fns[3] = { \
+ gen_helper_##NAME##_b, \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w \
+ }; \
+ return do_opiwv_widen(s, a, fns[s->sew]); \
+}
+
+GEN_OPIWV_WIDEN_TRANS(vwaddu_wv)
+GEN_OPIWV_WIDEN_TRANS(vwadd_wv)
+GEN_OPIWV_WIDEN_TRANS(vwsubu_wv)
+GEN_OPIWV_WIDEN_TRANS(vwsub_wv)
+
+/* WIDEN OPIVX with WIDEN */
+static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, true) &&
+ (s->lmul < 0x3) && (s->sew < 0x3));
+}
+
+static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a,
+ gen_helper_opivx *fn)
+{
+ if (opiwx_widen_check(s, a)) {
+ return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
+ }
+ return false;
+}
+
+#define GEN_OPIWX_WIDEN_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_opivx * const fns[3] = { \
+ gen_helper_##NAME##_b, \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w \
+ }; \
+ return do_opiwx_widen(s, a, fns[s->sew]); \
+}
+
+GEN_OPIWX_WIDEN_TRANS(vwaddu_wx)
+GEN_OPIWX_WIDEN_TRANS(vwadd_wx)
+GEN_OPIWX_WIDEN_TRANS(vwsubu_wx)
+GEN_OPIWX_WIDEN_TRANS(vwsub_wx)
+
+/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */
+/* OPIVV without GVEC IR */
+#define GEN_OPIVV_TRANS(NAME, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (CHECK(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_4_ptr * const fns[4] = { \
+ gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs1), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+/*
+ * For vadc and vsbc, an illegal instruction exception is raised if the
+ * destination vector register is v0 and LMUL > 1. (Section 12.3)
+ */
+static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ ((a->rd != 0) || (s->lmul == 0)));
+}
+
+GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check)
+GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check)
+
+/*
+ * For vmadc and vmsbc, an illegal instruction exception is raised if the
+ * destination vector register overlaps a source vector register group.
+ */
+static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) &&
+ vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul));
+}
+
+GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check)
+GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check)
+
+static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ ((a->rd != 0) || (s->lmul == 0)));
+}
+
+/* OPIVX without GVEC IR */
+#define GEN_OPIVX_TRANS(NAME, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (CHECK(s, a)) { \
+ static gen_helper_opivx * const fns[4] = { \
+ gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
+ }; \
+ \
+ return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
+ } \
+ return false; \
+}
+
+GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check)
+GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check)
+
+static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul));
+}
+
+GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check)
+GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check)
+
+/* OPIVI without GVEC IR */
+#define GEN_OPIVI_TRANS(NAME, ZX, OPIVX, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (CHECK(s, a)) { \
+ static gen_helper_opivx * const fns[4] = { \
+ gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \
+ gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \
+ }; \
+ return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \
+ fns[s->sew], s, ZX); \
+ } \
+ return false; \
+}
+
+GEN_OPIVI_TRANS(vadc_vim, 0, vadc_vxm, opivx_vadc_check)
+GEN_OPIVI_TRANS(vmadc_vim, 0, vmadc_vxm, opivx_vmadc_check)
+
+/* Vector Bitwise Logical Instructions */
+GEN_OPIVV_GVEC_TRANS(vand_vv, and)
+GEN_OPIVV_GVEC_TRANS(vor_vv, or)
+GEN_OPIVV_GVEC_TRANS(vxor_vv, xor)
+GEN_OPIVX_GVEC_TRANS(vand_vx, ands)
+GEN_OPIVX_GVEC_TRANS(vor_vx, ors)
+GEN_OPIVX_GVEC_TRANS(vxor_vx, xors)
+GEN_OPIVI_GVEC_TRANS(vand_vi, 0, vand_vx, andi)
+GEN_OPIVI_GVEC_TRANS(vor_vi, 0, vor_vx, ori)
+GEN_OPIVI_GVEC_TRANS(vxor_vi, 0, vxor_vx, xori)
+
+/* Vector Single-Width Bit Shift Instructions */
+GEN_OPIVV_GVEC_TRANS(vsll_vv, shlv)
+GEN_OPIVV_GVEC_TRANS(vsrl_vv, shrv)
+GEN_OPIVV_GVEC_TRANS(vsra_vv, sarv)
+
+typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32,
+ uint32_t, uint32_t);
+
+static inline bool
+do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn,
+ gen_helper_opivx *fn)
+{
+ if (!opivx_check(s, a)) {
+ return false;
+ }
+
+ if (a->vm && s->vl_eq_vlmax) {
+ TCGv_i32 src1 = tcg_temp_new_i32();
+
+ tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE));
+ tcg_gen_extract_i32(src1, src1, 0, s->sew + 3);
+ gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
+ src1, MAXSZ(s), MAXSZ(s));
+
+ tcg_temp_free_i32(src1);
+ return true;
+ }
+ return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
+}
+
+#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_opivx * const fns[4] = { \
+ gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
+ }; \
+ \
+ return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
+}
+
+GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx, shls)
+GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx, shrs)
+GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx, sars)
+
+GEN_OPIVI_GVEC_TRANS(vsll_vi, 1, vsll_vx, shli)
+GEN_OPIVI_GVEC_TRANS(vsrl_vi, 1, vsrl_vx, shri)
+GEN_OPIVI_GVEC_TRANS(vsra_vi, 1, vsra_vx, sari)
+
+/* Vector Narrowing Integer Right Shift Instructions */
+static bool opivv_narrow_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, true) &&
+ vext_check_reg(s, a->rs1, false) &&
+ vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2,
+ 2 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3));
+}
+
+/* OPIVV with NARROW */
+#define GEN_OPIVV_NARROW_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (opivv_narrow_check(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_4_ptr * const fns[3] = { \
+ gen_helper_##NAME##_b, \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs1), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+GEN_OPIVV_NARROW_TRANS(vnsra_vv)
+GEN_OPIVV_NARROW_TRANS(vnsrl_vv)
+
+static bool opivx_narrow_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, true) &&
+ vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2,
+ 2 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3));
+}
+
+/* OPIVX with NARROW */
+#define GEN_OPIVX_NARROW_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (opivx_narrow_check(s, a)) { \
+ static gen_helper_opivx * const fns[3] = { \
+ gen_helper_##NAME##_b, \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, \
+ }; \
+ return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
+ } \
+ return false; \
+}
+
+GEN_OPIVX_NARROW_TRANS(vnsra_vx)
+GEN_OPIVX_NARROW_TRANS(vnsrl_vx)
+
+/* OPIVI with NARROW */
+#define GEN_OPIVI_NARROW_TRANS(NAME, ZX, OPIVX) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (opivx_narrow_check(s, a)) { \
+ static gen_helper_opivx * const fns[3] = { \
+ gen_helper_##OPIVX##_b, \
+ gen_helper_##OPIVX##_h, \
+ gen_helper_##OPIVX##_w, \
+ }; \
+ return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \
+ fns[s->sew], s, ZX); \
+ } \
+ return false; \
+}
+
+GEN_OPIVI_NARROW_TRANS(vnsra_vi, 1, vnsra_vx)
+GEN_OPIVI_NARROW_TRANS(vnsrl_vi, 1, vnsrl_vx)
+
+/* Vector Integer Comparison Instructions */
+/*
+ * For all comparison instructions, an illegal instruction exception is raised
+ * if the destination vector register overlaps a source vector register group
+ * and LMUL > 1.
+ */
+static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) &&
+ vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) ||
+ (s->lmul == 0)));
+}
+GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check)
+GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check)
+GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check)
+GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check)
+GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check)
+GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check)
+
+static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rs2, false) &&
+ (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) ||
+ (s->lmul == 0)));
+}
+
+GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check)
+GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check)
+GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check)
+GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check)
+GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check)
+GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check)
+GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check)
+GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check)
+
+GEN_OPIVI_TRANS(vmseq_vi, 0, vmseq_vx, opivx_cmp_check)
+GEN_OPIVI_TRANS(vmsne_vi, 0, vmsne_vx, opivx_cmp_check)
+GEN_OPIVI_TRANS(vmsleu_vi, 1, vmsleu_vx, opivx_cmp_check)
+GEN_OPIVI_TRANS(vmsle_vi, 0, vmsle_vx, opivx_cmp_check)
+GEN_OPIVI_TRANS(vmsgtu_vi, 1, vmsgtu_vx, opivx_cmp_check)
+GEN_OPIVI_TRANS(vmsgt_vi, 0, vmsgt_vx, opivx_cmp_check)
+
+/* Vector Integer Min/Max Instructions */
+GEN_OPIVV_GVEC_TRANS(vminu_vv, umin)
+GEN_OPIVV_GVEC_TRANS(vmin_vv, smin)
+GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax)
+GEN_OPIVV_GVEC_TRANS(vmax_vv, smax)
+GEN_OPIVX_TRANS(vminu_vx, opivx_check)
+GEN_OPIVX_TRANS(vmin_vx, opivx_check)
+GEN_OPIVX_TRANS(vmaxu_vx, opivx_check)
+GEN_OPIVX_TRANS(vmax_vx, opivx_check)
+
+/* Vector Single-Width Integer Multiply Instructions */
+GEN_OPIVV_GVEC_TRANS(vmul_vv, mul)
+GEN_OPIVV_TRANS(vmulh_vv, opivv_check)
+GEN_OPIVV_TRANS(vmulhu_vv, opivv_check)
+GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check)
+GEN_OPIVX_GVEC_TRANS(vmul_vx, muls)
+GEN_OPIVX_TRANS(vmulh_vx, opivx_check)
+GEN_OPIVX_TRANS(vmulhu_vx, opivx_check)
+GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check)
+
+/* Vector Integer Divide Instructions */
+GEN_OPIVV_TRANS(vdivu_vv, opivv_check)
+GEN_OPIVV_TRANS(vdiv_vv, opivv_check)
+GEN_OPIVV_TRANS(vremu_vv, opivv_check)
+GEN_OPIVV_TRANS(vrem_vv, opivv_check)
+GEN_OPIVX_TRANS(vdivu_vx, opivx_check)
+GEN_OPIVX_TRANS(vdiv_vx, opivx_check)
+GEN_OPIVX_TRANS(vremu_vx, opivx_check)
+GEN_OPIVX_TRANS(vrem_vx, opivx_check)
+
+/* Vector Widening Integer Multiply Instructions */
+GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check)
+GEN_OPIVX_WIDEN_TRANS(vwmul_vx)
+GEN_OPIVX_WIDEN_TRANS(vwmulu_vx)
+GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx)
+
+/* Vector Single-Width Integer Multiply-Add Instructions */
+GEN_OPIVV_TRANS(vmacc_vv, opivv_check)
+GEN_OPIVV_TRANS(vnmsac_vv, opivv_check)
+GEN_OPIVV_TRANS(vmadd_vv, opivv_check)
+GEN_OPIVV_TRANS(vnmsub_vv, opivv_check)
+GEN_OPIVX_TRANS(vmacc_vx, opivx_check)
+GEN_OPIVX_TRANS(vnmsac_vx, opivx_check)
+GEN_OPIVX_TRANS(vmadd_vx, opivx_check)
+GEN_OPIVX_TRANS(vnmsub_vx, opivx_check)
+
+/* Vector Widening Integer Multiply-Add Instructions */
+GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check)
+GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx)
+GEN_OPIVX_WIDEN_TRANS(vwmacc_vx)
+GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx)
+GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx)
+
+/* Vector Integer Merge and Move Instructions */
+static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a)
+{
+ if (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs1, false)) {
+
+ if (s->vl_eq_vlmax) {
+ tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd),
+ vreg_ofs(s, a->rs1),
+ MAXSZ(s), MAXSZ(s));
+ } else {
+ uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
+ static gen_helper_gvec_2_ptr * const fns[4] = {
+ gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h,
+ gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d,
+ };
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1),
+ cpu_env, s->vlen / 8, s->vlen / 8, data,
+ fns[s->sew]);
+ gen_set_label(over);
+ }
+ return true;
+ }
+ return false;
+}
+
+typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32);
+static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a)
+{
+ if (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false)) {
+
+ TCGv s1;
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ s1 = get_gpr(s, a->rs1, EXT_SIGN);
+
+ if (s->vl_eq_vlmax) {
+ tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd),
+ MAXSZ(s), MAXSZ(s), s1);
+ } else {
+ TCGv_i32 desc;
+ TCGv_i64 s1_i64 = tcg_temp_new_i64();
+ TCGv_ptr dest = tcg_temp_new_ptr();
+ uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
+ static gen_helper_vmv_vx * const fns[4] = {
+ gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
+ gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
+ };
+
+ tcg_gen_ext_tl_i64(s1_i64, s1);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
+ fns[s->sew](dest, s1_i64, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_i64(s1_i64);
+ }
+
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
+
+static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a)
+{
+ if (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false)) {
+
+ int64_t simm = sextract64(a->rs1, 0, 5);
+ if (s->vl_eq_vlmax) {
+ tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd),
+ MAXSZ(s), MAXSZ(s), simm);
+ } else {
+ TCGv_i32 desc;
+ TCGv_i64 s1;
+ TCGv_ptr dest;
+ uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
+ static gen_helper_vmv_vx * const fns[4] = {
+ gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
+ gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
+ };
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ s1 = tcg_constant_i64(simm);
+ dest = tcg_temp_new_ptr();
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
+ fns[s->sew](dest, s1, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ gen_set_label(over);
+ }
+ return true;
+ }
+ return false;
+}
+
+GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check)
+GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check)
+GEN_OPIVI_TRANS(vmerge_vim, 0, vmerge_vxm, opivx_vadc_check)
+
+/*
+ *** Vector Fixed-Point Arithmetic Instructions
+ */
+
+/* Vector Single-Width Saturating Add and Subtract */
+GEN_OPIVV_TRANS(vsaddu_vv, opivv_check)
+GEN_OPIVV_TRANS(vsadd_vv, opivv_check)
+GEN_OPIVV_TRANS(vssubu_vv, opivv_check)
+GEN_OPIVV_TRANS(vssub_vv, opivv_check)
+GEN_OPIVX_TRANS(vsaddu_vx, opivx_check)
+GEN_OPIVX_TRANS(vsadd_vx, opivx_check)
+GEN_OPIVX_TRANS(vssubu_vx, opivx_check)
+GEN_OPIVX_TRANS(vssub_vx, opivx_check)
+GEN_OPIVI_TRANS(vsaddu_vi, 1, vsaddu_vx, opivx_check)
+GEN_OPIVI_TRANS(vsadd_vi, 0, vsadd_vx, opivx_check)
+
+/* Vector Single-Width Averaging Add and Subtract */
+GEN_OPIVV_TRANS(vaadd_vv, opivv_check)
+GEN_OPIVV_TRANS(vasub_vv, opivv_check)
+GEN_OPIVX_TRANS(vaadd_vx, opivx_check)
+GEN_OPIVX_TRANS(vasub_vx, opivx_check)
+GEN_OPIVI_TRANS(vaadd_vi, 0, vaadd_vx, opivx_check)
+
+/* Vector Single-Width Fractional Multiply with Rounding and Saturation */
+GEN_OPIVV_TRANS(vsmul_vv, opivv_check)
+GEN_OPIVX_TRANS(vsmul_vx, opivx_check)
+
+/* Vector Widening Saturating Scaled Multiply-Add */
+GEN_OPIVV_WIDEN_TRANS(vwsmaccu_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwsmacc_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwsmaccsu_vv, opivv_widen_check)
+GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx)
+GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx)
+GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx)
+GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx)
+
+/* Vector Single-Width Scaling Shift Instructions */
+GEN_OPIVV_TRANS(vssrl_vv, opivv_check)
+GEN_OPIVV_TRANS(vssra_vv, opivv_check)
+GEN_OPIVX_TRANS(vssrl_vx, opivx_check)
+GEN_OPIVX_TRANS(vssra_vx, opivx_check)
+GEN_OPIVI_TRANS(vssrl_vi, 1, vssrl_vx, opivx_check)
+GEN_OPIVI_TRANS(vssra_vi, 0, vssra_vx, opivx_check)
+
+/* Vector Narrowing Fixed-Point Clip Instructions */
+GEN_OPIVV_NARROW_TRANS(vnclipu_vv)
+GEN_OPIVV_NARROW_TRANS(vnclip_vv)
+GEN_OPIVX_NARROW_TRANS(vnclipu_vx)
+GEN_OPIVX_NARROW_TRANS(vnclip_vx)
+GEN_OPIVI_NARROW_TRANS(vnclipu_vi, 1, vnclipu_vx)
+GEN_OPIVI_NARROW_TRANS(vnclip_vi, 1, vnclip_vx)
+
+/*
+ *** Vector Float Point Arithmetic Instructions
+ */
+/* Vector Single-Width Floating-Point Add/Subtract Instructions */
+
+/*
+ * If the current SEW does not correspond to a supported IEEE floating-point
+ * type, an illegal instruction exception is raised.
+ */
+static bool opfvv_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ (s->sew != 0));
+}
+
+/* OPFVV without GVEC IR */
+#define GEN_OPFVV_TRANS(NAME, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (CHECK(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_4_ptr * const fns[3] = { \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, \
+ gen_helper_##NAME##_d, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ gen_set_rm(s, 7); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs1), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew - 1]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+GEN_OPFVV_TRANS(vfadd_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfsub_vv, opfvv_check)
+
+typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr,
+ TCGv_env, TCGv_i32);
+
+static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
+ uint32_t data, gen_helper_opfvf *fn, DisasContext *s)
+{
+ TCGv_ptr dest, src2, mask;
+ TCGv_i32 desc;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ src2 = tcg_temp_new_ptr();
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, cpu_fpr[rs1], src2, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(src2);
+ gen_set_label(over);
+ return true;
+}
+
+static bool opfvf_check(DisasContext *s, arg_rmrr *a)
+{
+/*
+ * If the current SEW does not correspond to a supported IEEE floating-point
+ * type, an illegal instruction exception is raised
+ */
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ (s->sew != 0));
+}
+
+/* OPFVF without GVEC IR */
+#define GEN_OPFVF_TRANS(NAME, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (CHECK(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_opfvf *const fns[3] = { \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, \
+ gen_helper_##NAME##_d, \
+ }; \
+ gen_set_rm(s, 7); \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
+ fns[s->sew - 1], s); \
+ } \
+ return false; \
+}
+
+GEN_OPFVF_TRANS(vfadd_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfsub_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfrsub_vf, opfvf_check)
+
+/* Vector Widening Floating-Point Add/Subtract Instructions */
+static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
+ 1 << s->lmul) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
+ 1 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
+}
+
+/* OPFVV with WIDEN */
+#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (CHECK(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_4_ptr * const fns[2] = { \
+ gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ gen_set_rm(s, 7); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs1), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew - 1]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check)
+GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check)
+
+static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
+ 1 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
+}
+
+/* OPFVF with WIDEN */
+#define GEN_OPFVF_WIDEN_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (opfvf_widen_check(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_opfvf *const fns[2] = { \
+ gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
+ }; \
+ gen_set_rm(s, 7); \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
+ fns[s->sew - 1], s); \
+ } \
+ return false; \
+}
+
+GEN_OPFVF_WIDEN_TRANS(vfwadd_vf)
+GEN_OPFVF_WIDEN_TRANS(vfwsub_vf)
+
+static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, true) &&
+ vext_check_reg(s, a->rs1, false) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
+ 1 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
+}
+
+/* WIDEN OPFVV with WIDEN */
+#define GEN_OPFWV_WIDEN_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (opfwv_widen_check(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_4_ptr * const fns[2] = { \
+ gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ gen_set_rm(s, 7); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs1), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew - 1]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+GEN_OPFWV_WIDEN_TRANS(vfwadd_wv)
+GEN_OPFWV_WIDEN_TRANS(vfwsub_wv)
+
+static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, true) &&
+ (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
+}
+
+/* WIDEN OPFVF with WIDEN */
+#define GEN_OPFWF_WIDEN_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (opfwf_widen_check(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_opfvf *const fns[2] = { \
+ gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
+ }; \
+ gen_set_rm(s, 7); \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
+ fns[s->sew - 1], s); \
+ } \
+ return false; \
+}
+
+GEN_OPFWF_WIDEN_TRANS(vfwadd_wf)
+GEN_OPFWF_WIDEN_TRANS(vfwsub_wf)
+
+/* Vector Single-Width Floating-Point Multiply/Divide Instructions */
+GEN_OPFVV_TRANS(vfmul_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check)
+GEN_OPFVF_TRANS(vfmul_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfdiv_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check)
+
+/* Vector Widening Floating-Point Multiply */
+GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check)
+GEN_OPFVF_WIDEN_TRANS(vfwmul_vf)
+
+/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
+GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check)
+GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check)
+
+/* Vector Widening Floating-Point Fused Multiply-Add Instructions */
+GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check)
+GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check)
+GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check)
+GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check)
+GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf)
+GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf)
+GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf)
+GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf)
+
+/* Vector Floating-Point Square-Root Instruction */
+
+/*
+ * If the current SEW does not correspond to a supported IEEE floating-point
+ * type, an illegal instruction exception is raised
+ */
+static bool opfv_check(DisasContext *s, arg_rmr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ (s->sew != 0));
+}
+
+#define GEN_OPFV_TRANS(NAME, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
+{ \
+ if (CHECK(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_3_ptr * const fns[3] = { \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, \
+ gen_helper_##NAME##_d, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ gen_set_rm(s, 7); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew - 1]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+GEN_OPFV_TRANS(vfsqrt_v, opfv_check)
+
+/* Vector Floating-Point MIN/MAX Instructions */
+GEN_OPFVV_TRANS(vfmin_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfmax_vv, opfvv_check)
+GEN_OPFVF_TRANS(vfmin_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfmax_vf, opfvf_check)
+
+/* Vector Floating-Point Sign-Injection Instructions */
+GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check)
+GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check)
+
+/* Vector Floating-Point Compare Instructions */
+static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ (s->sew != 0) &&
+ ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) &&
+ vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) ||
+ (s->lmul == 0)));
+}
+
+GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check)
+GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check)
+GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check)
+GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check)
+GEN_OPFVV_TRANS(vmford_vv, opfvv_cmp_check)
+
+static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rs2, false) &&
+ (s->sew != 0) &&
+ (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) ||
+ (s->lmul == 0)));
+}
+
+GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check)
+GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check)
+GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check)
+GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check)
+GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check)
+GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check)
+GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check)
+
+/* Vector Floating-Point Classify Instruction */
+GEN_OPFV_TRANS(vfclass_v, opfv_check)
+
+/* Vector Floating-Point Merge Instruction */
+GEN_OPFVF_TRANS(vfmerge_vfm, opfvf_check)
+
+static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
+{
+ if (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ (s->sew != 0)) {
+
+ if (s->vl_eq_vlmax) {
+ tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
+ MAXSZ(s), MAXSZ(s), cpu_fpr[a->rs1]);
+ } else {
+ TCGv_ptr dest;
+ TCGv_i32 desc;
+ uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
+ static gen_helper_vmv_vx * const fns[3] = {
+ gen_helper_vmv_v_x_h,
+ gen_helper_vmv_v_x_w,
+ gen_helper_vmv_v_x_d,
+ };
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
+ fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ gen_set_label(over);
+ }
+ return true;
+ }
+ return false;
+}
+
+/* Single-Width Floating-Point/Integer Type-Convert Instructions */
+GEN_OPFV_TRANS(vfcvt_xu_f_v, opfv_check)
+GEN_OPFV_TRANS(vfcvt_x_f_v, opfv_check)
+GEN_OPFV_TRANS(vfcvt_f_xu_v, opfv_check)
+GEN_OPFV_TRANS(vfcvt_f_x_v, opfv_check)
+
+/* Widening Floating-Point/Integer Type-Convert Instructions */
+
+/*
+ * If the current SEW does not correspond to a supported IEEE floating-point
+ * type, an illegal instruction exception is raised
+ */
+static bool opfv_widen_check(DisasContext *s, arg_rmr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
+ 1 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
+}
+
+#define GEN_OPFV_WIDEN_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
+{ \
+ if (opfv_widen_check(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_3_ptr * const fns[2] = { \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ gen_set_rm(s, 7); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew - 1]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v)
+GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v)
+GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v)
+GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v)
+GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v)
+
+/* Narrowing Floating-Point/Integer Type-Convert Instructions */
+
+/*
+ * If the current SEW does not correspond to a supported IEEE floating-point
+ * type, an illegal instruction exception is raised
+ */
+static bool opfv_narrow_check(DisasContext *s, arg_rmr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, true) &&
+ vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2,
+ 2 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
+}
+
+#define GEN_OPFV_NARROW_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
+{ \
+ if (opfv_narrow_check(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_3_ptr * const fns[2] = { \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ gen_set_rm(s, 7); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew - 1]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v)
+GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v)
+GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v)
+GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v)
+GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v)
+
+/*
+ *** Vector Reduction Operations
+ */
+/* Vector Single-Width Integer Reduction Instructions */
+static bool reduction_check(DisasContext *s, arg_rmrr *a)
+{
+ return vext_check_isa_ill(s) && vext_check_reg(s, a->rs2, false);
+}
+
+GEN_OPIVV_TRANS(vredsum_vs, reduction_check)
+GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check)
+GEN_OPIVV_TRANS(vredmax_vs, reduction_check)
+GEN_OPIVV_TRANS(vredminu_vs, reduction_check)
+GEN_OPIVV_TRANS(vredmin_vs, reduction_check)
+GEN_OPIVV_TRANS(vredand_vs, reduction_check)
+GEN_OPIVV_TRANS(vredor_vs, reduction_check)
+GEN_OPIVV_TRANS(vredxor_vs, reduction_check)
+
+/* Vector Widening Integer Reduction Instructions */
+GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_check)
+GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_check)
+
+/* Vector Single-Width Floating-Point Reduction Instructions */
+GEN_OPFVV_TRANS(vfredsum_vs, reduction_check)
+GEN_OPFVV_TRANS(vfredmax_vs, reduction_check)
+GEN_OPFVV_TRANS(vfredmin_vs, reduction_check)
+
+/* Vector Widening Floating-Point Reduction Instructions */
+GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, reduction_check)
+
+/*
+ *** Vector Mask Operations
+ */
+
+/* Vector Mask-Register Logical Instructions */
+#define GEN_MM_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_r *a) \
+{ \
+ if (vext_check_isa_ill(s)) { \
+ uint32_t data = 0; \
+ gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \
+ TCGLabel *over = gen_new_label(); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs1), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, fn); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+GEN_MM_TRANS(vmand_mm)
+GEN_MM_TRANS(vmnand_mm)
+GEN_MM_TRANS(vmandnot_mm)
+GEN_MM_TRANS(vmxor_mm)
+GEN_MM_TRANS(vmor_mm)
+GEN_MM_TRANS(vmnor_mm)
+GEN_MM_TRANS(vmornot_mm)
+GEN_MM_TRANS(vmxnor_mm)
+
+/* Vector mask population count vmpopc */
+static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a)
+{
+ if (vext_check_isa_ill(s)) {
+ TCGv_ptr src2, mask;
+ TCGv dst;
+ TCGv_i32 desc;
+ uint32_t data = 0;
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+
+ mask = tcg_temp_new_ptr();
+ src2 = tcg_temp_new_ptr();
+ dst = dest_gpr(s, a->rd);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ gen_helper_vmpopc_m(dst, mask, src2, cpu_env, desc);
+ gen_set_gpr(s, a->rd, dst);
+
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(src2);
+ return true;
+ }
+ return false;
+}
+
+/* vmfirst find-first-set mask bit */
+static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a)
+{
+ if (vext_check_isa_ill(s)) {
+ TCGv_ptr src2, mask;
+ TCGv dst;
+ TCGv_i32 desc;
+ uint32_t data = 0;
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+
+ mask = tcg_temp_new_ptr();
+ src2 = tcg_temp_new_ptr();
+ dst = dest_gpr(s, a->rd);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ gen_helper_vmfirst_m(dst, mask, src2, cpu_env, desc);
+ gen_set_gpr(s, a->rd, dst);
+
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(src2);
+ return true;
+ }
+ return false;
+}
+
+/* vmsbf.m set-before-first mask bit */
+/* vmsif.m set-includ-first mask bit */
+/* vmsof.m set-only-first mask bit */
+#define GEN_M_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
+{ \
+ if (vext_check_isa_ill(s)) { \
+ uint32_t data = 0; \
+ gen_helper_gvec_3_ptr *fn = gen_helper_##NAME; \
+ TCGLabel *over = gen_new_label(); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \
+ vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \
+ cpu_env, s->vlen / 8, s->vlen / 8, \
+ data, fn); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+GEN_M_TRANS(vmsbf_m)
+GEN_M_TRANS(vmsif_m)
+GEN_M_TRANS(vmsof_m)
+
+/* Vector Iota Instruction */
+static bool trans_viota_m(DisasContext *s, arg_viota_m *a)
+{
+ if (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 1) &&
+ (a->vm != 0 || a->rd != 0)) {
+ uint32_t data = 0;
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ static gen_helper_gvec_3_ptr * const fns[4] = {
+ gen_helper_viota_m_b, gen_helper_viota_m_h,
+ gen_helper_viota_m_w, gen_helper_viota_m_d,
+ };
+ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
+ vreg_ofs(s, a->rs2), cpu_env,
+ s->vlen / 8, s->vlen / 8, data, fns[s->sew]);
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
+
+/* Vector Element Index Instruction */
+static bool trans_vid_v(DisasContext *s, arg_vid_v *a)
+{
+ if (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false)) {
+ uint32_t data = 0;
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ static gen_helper_gvec_2_ptr * const fns[4] = {
+ gen_helper_vid_v_b, gen_helper_vid_v_h,
+ gen_helper_vid_v_w, gen_helper_vid_v_d,
+ };
+ tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
+ cpu_env, s->vlen / 8, s->vlen / 8,
+ data, fns[s->sew]);
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
+
+/*
+ *** Vector Permutation Instructions
+ */
+
+/* Integer Extract Instruction */
+
+static void load_element(TCGv_i64 dest, TCGv_ptr base,
+ int ofs, int sew)
+{
+ switch (sew) {
+ case MO_8:
+ tcg_gen_ld8u_i64(dest, base, ofs);
+ break;
+ case MO_16:
+ tcg_gen_ld16u_i64(dest, base, ofs);
+ break;
+ case MO_32:
+ tcg_gen_ld32u_i64(dest, base, ofs);
+ break;
+ case MO_64:
+ tcg_gen_ld_i64(dest, base, ofs);
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+}
+
+/* offset of the idx element with base regsiter r */
+static uint32_t endian_ofs(DisasContext *s, int r, int idx)
+{
+#ifdef HOST_WORDS_BIGENDIAN
+ return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew);
+#else
+ return vreg_ofs(s, r) + (idx << s->sew);
+#endif
+}
+
+/* adjust the index according to the endian */
+static void endian_adjust(TCGv_i32 ofs, int sew)
+{
+#ifdef HOST_WORDS_BIGENDIAN
+ tcg_gen_xori_i32(ofs, ofs, 7 >> sew);
+#endif
+}
+
+/* Load idx >= VLMAX ? 0 : vreg[idx] */
+static void vec_element_loadx(DisasContext *s, TCGv_i64 dest,
+ int vreg, TCGv idx, int vlmax)
+{
+ TCGv_i32 ofs = tcg_temp_new_i32();
+ TCGv_ptr base = tcg_temp_new_ptr();
+ TCGv_i64 t_idx = tcg_temp_new_i64();
+ TCGv_i64 t_vlmax, t_zero;
+
+ /*
+ * Mask the index to the length so that we do
+ * not produce an out-of-range load.
+ */
+ tcg_gen_trunc_tl_i32(ofs, idx);
+ tcg_gen_andi_i32(ofs, ofs, vlmax - 1);
+
+ /* Convert the index to an offset. */
+ endian_adjust(ofs, s->sew);
+ tcg_gen_shli_i32(ofs, ofs, s->sew);
+
+ /* Convert the index to a pointer. */
+ tcg_gen_ext_i32_ptr(base, ofs);
+ tcg_gen_add_ptr(base, base, cpu_env);
+
+ /* Perform the load. */
+ load_element(dest, base,
+ vreg_ofs(s, vreg), s->sew);
+ tcg_temp_free_ptr(base);
+ tcg_temp_free_i32(ofs);
+
+ /* Flush out-of-range indexing to zero. */
+ t_vlmax = tcg_constant_i64(vlmax);
+ t_zero = tcg_constant_i64(0);
+ tcg_gen_extu_tl_i64(t_idx, idx);
+
+ tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx,
+ t_vlmax, dest, t_zero);
+
+ tcg_temp_free_i64(t_idx);
+}
+
+static void vec_element_loadi(DisasContext *s, TCGv_i64 dest,
+ int vreg, int idx)
+{
+ load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew);
+}
+
+static bool trans_vext_x_v(DisasContext *s, arg_r *a)
+{
+ TCGv_i64 tmp = tcg_temp_new_i64();
+ TCGv dest = dest_gpr(s, a->rd);
+
+ if (a->rs1 == 0) {
+ /* Special case vmv.x.s rd, vs2. */
+ vec_element_loadi(s, tmp, a->rs2, 0);
+ } else {
+ /* This instruction ignores LMUL and vector register groups */
+ int vlmax = s->vlen >> (3 + s->sew);
+ vec_element_loadx(s, tmp, a->rs2, cpu_gpr[a->rs1], vlmax);
+ }
+
+ tcg_gen_trunc_i64_tl(dest, tmp);
+ gen_set_gpr(s, a->rd, dest);
+
+ tcg_temp_free_i64(tmp);
+ return true;
+}
+
+/* Integer Scalar Move Instruction */
+
+static void store_element(TCGv_i64 val, TCGv_ptr base,
+ int ofs, int sew)
+{
+ switch (sew) {
+ case MO_8:
+ tcg_gen_st8_i64(val, base, ofs);
+ break;
+ case MO_16:
+ tcg_gen_st16_i64(val, base, ofs);
+ break;
+ case MO_32:
+ tcg_gen_st32_i64(val, base, ofs);
+ break;
+ case MO_64:
+ tcg_gen_st_i64(val, base, ofs);
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+}
+
+/*
+ * Store vreg[idx] = val.
+ * The index must be in range of VLMAX.
+ */
+static void vec_element_storei(DisasContext *s, int vreg,
+ int idx, TCGv_i64 val)
+{
+ store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew);
+}
+
+/* vmv.s.x vd, rs1 # vd[0] = rs1 */
+static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a)
+{
+ if (vext_check_isa_ill(s)) {
+ /* This instruction ignores LMUL and vector register groups */
+ int maxsz = s->vlen >> 3;
+ TCGv_i64 t1;
+ TCGLabel *over = gen_new_label();
+
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+ tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), maxsz, maxsz, 0);
+ if (a->rs1 == 0) {
+ goto done;
+ }
+
+ t1 = tcg_temp_new_i64();
+ tcg_gen_extu_tl_i64(t1, cpu_gpr[a->rs1]);
+ vec_element_storei(s, a->rd, 0, t1);
+ tcg_temp_free_i64(t1);
+ done:
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
+
+/* Floating-Point Scalar Move Instructions */
+static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a)
+{
+ if (!s->vill && has_ext(s, RVF) &&
+ (s->mstatus_fs != 0) && (s->sew != 0)) {
+ unsigned int len = 8 << s->sew;
+
+ vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0);
+ if (len < 64) {
+ tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd],
+ MAKE_64BIT_MASK(len, 64 - len));
+ }
+
+ mark_fs_dirty(s);
+ return true;
+ }
+ return false;
+}
+
+/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */
+static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
+{
+ if (!s->vill && has_ext(s, RVF) && (s->sew != 0)) {
+ TCGv_i64 t1;
+ /* The instructions ignore LMUL and vector register group. */
+ uint32_t vlmax = s->vlen >> 3;
+
+ /* if vl == 0, skip vector register write back */
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ /* zeroed all elements */
+ tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), vlmax, vlmax, 0);
+
+ /* NaN-box f[rs1] as necessary for SEW */
+ t1 = tcg_temp_new_i64();
+ if (s->sew == MO_64 && !has_ext(s, RVD)) {
+ tcg_gen_ori_i64(t1, cpu_fpr[a->rs1], MAKE_64BIT_MASK(32, 32));
+ } else {
+ tcg_gen_mov_i64(t1, cpu_fpr[a->rs1]);
+ }
+ vec_element_storei(s, a->rd, 0, t1);
+ tcg_temp_free_i64(t1);
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
+
+/* Vector Slide Instructions */
+static bool slideup_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ (a->rd != a->rs2));
+}
+
+GEN_OPIVX_TRANS(vslideup_vx, slideup_check)
+GEN_OPIVX_TRANS(vslide1up_vx, slideup_check)
+GEN_OPIVI_TRANS(vslideup_vi, 1, vslideup_vx, slideup_check)
+
+GEN_OPIVX_TRANS(vslidedown_vx, opivx_check)
+GEN_OPIVX_TRANS(vslide1down_vx, opivx_check)
+GEN_OPIVI_TRANS(vslidedown_vi, 1, vslidedown_vx, opivx_check)
+
+/* Vector Register Gather Instruction */
+static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ (a->rd != a->rs2) && (a->rd != a->rs1));
+}
+
+GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check)
+
+static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ (a->rd != a->rs2));
+}
+
+/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */
+static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a)
+{
+ if (!vrgather_vx_check(s, a)) {
+ return false;
+ }
+
+ if (a->vm && s->vl_eq_vlmax) {
+ int vlmax = s->vlen / s->mlen;
+ TCGv_i64 dest = tcg_temp_new_i64();
+
+ if (a->rs1 == 0) {
+ vec_element_loadi(s, dest, a->rs2, 0);
+ } else {
+ vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax);
+ }
+
+ tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
+ MAXSZ(s), MAXSZ(s), dest);
+ tcg_temp_free_i64(dest);
+ } else {
+ static gen_helper_opivx * const fns[4] = {
+ gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
+ gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
+ };
+ return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);
+ }
+ return true;
+}
+
+/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */
+static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a)
+{
+ if (!vrgather_vx_check(s, a)) {
+ return false;
+ }
+
+ if (a->vm && s->vl_eq_vlmax) {
+ if (a->rs1 >= s->vlen / s->mlen) {
+ tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd),
+ MAXSZ(s), MAXSZ(s), 0);
+ } else {
+ tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd),
+ endian_ofs(s, a->rs2, a->rs1),
+ MAXSZ(s), MAXSZ(s));
+ }
+ } else {
+ static gen_helper_opivx * const fns[4] = {
+ gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
+ gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
+ };
+ return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s, 1);
+ }
+ return true;
+}
+
+/* Vector Compress Instruction */
+static bool vcompress_vm_check(DisasContext *s, arg_r *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs1, 1) &&
+ (a->rd != a->rs2));
+}
+
+static bool trans_vcompress_vm(DisasContext *s, arg_r *a)
+{
+ if (vcompress_vm_check(s, a)) {
+ uint32_t data = 0;
+ static gen_helper_gvec_4_ptr * const fns[4] = {
+ gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h,
+ gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d,
+ };
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
+ vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
+ cpu_env, s->vlen / 8, s->vlen / 8, data,
+ fns[s->sew]);
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}