@@ -1296,3 +1296,17 @@ vstelm_d 0011 00010001 0 . ........ ..... ..... @vr_i8i1
vstelm_w 0011 00010010 .. ........ ..... ..... @vr_i8i2
vstelm_h 0011 0001010 ... ........ ..... ..... @vr_i8i3
vstelm_b 0011 000110 .... ........ ..... ..... @vr_i8i4
+
+#
+# LoongArch LASX instructions
+#
+xvadd_b 0111 01000000 10100 ..... ..... ..... @vvv
+xvadd_h 0111 01000000 10101 ..... ..... ..... @vvv
+xvadd_w 0111 01000000 10110 ..... ..... ..... @vvv
+xvadd_d 0111 01000000 10111 ..... ..... ..... @vvv
+xvadd_q 0111 01010010 11010 ..... ..... ..... @vvv
+xvsub_b 0111 01000000 11000 ..... ..... ..... @vvv
+xvsub_h 0111 01000000 11001 ..... ..... ..... @vvv
+xvsub_w 0111 01000000 11010 ..... ..... ..... @vvv
+xvsub_d 0111 01000000 11011 ..... ..... ..... @vvv
+xvsub_q 0111 01010010 11011 ..... ..... ..... @vvv
@@ -1695,3 +1695,26 @@ INSN_LSX(vstelm_d, vr_ii)
INSN_LSX(vstelm_w, vr_ii)
INSN_LSX(vstelm_h, vr_ii)
INSN_LSX(vstelm_b, vr_ii)
+
+#define INSN_LASX(insn, type) \
+static bool trans_##insn(DisasContext *ctx, arg_##type * a) \
+{ \
+ output_##type ## _x(ctx, a, #insn); \
+ return true; \
+}
+
+static void output_vvv_x(DisasContext *ctx, arg_vvv * a, const char *mnemonic)
+{
+ output(ctx, mnemonic, "x%d, x%d, x%d", a->vd, a->vj, a->vk);
+}
+
+INSN_LASX(xvadd_b, vvv)
+INSN_LASX(xvadd_h, vvv)
+INSN_LASX(xvadd_w, vvv)
+INSN_LASX(xvadd_d, vvv)
+INSN_LASX(xvadd_q, vvv)
+INSN_LASX(xvsub_b, vvv)
+INSN_LASX(xvsub_h, vvv)
+INSN_LASX(xvsub_w, vvv)
+INSN_LASX(xvsub_d, vvv)
+INSN_LASX(xvsub_q, vvv)
@@ -124,6 +124,10 @@ static void loongarch_tr_init_disas_context(DisasContextBase *dcbase,
ctx->vl = LSX_LEN;
}
+ if (FIELD_EX64(env->cpucfg[2], CPUCFG2, LASX)) {
+ ctx->vl = LASX_LEN;
+ }
+
ctx->la64 = is_la64(env);
ctx->va32 = (ctx->base.tb->flags & HW_FLAGS_VA32) != 0;
@@ -193,6 +193,10 @@ static bool gvec_vvv_vl(DisasContext *ctx, arg_vvv *a,
uint32_t vj_ofs = vec_full_offset(a->vj);
uint32_t vk_ofs = vec_full_offset(a->vk);
+ if (!check_vec(ctx, oprsz)) {
+ return true;
+ }
+
func(mop, vd_ofs, vj_ofs, vk_ofs, oprsz, ctx->vl / 8);
return true;
}
@@ -201,13 +205,15 @@ static bool gvec_vvv(DisasContext *ctx, arg_vvv *a, MemOp mop,
void (*func)(unsigned, uint32_t, uint32_t,
uint32_t, uint32_t, uint32_t))
{
- if (!check_vec(ctx, 16)) {
- return true;
- }
-
return gvec_vvv_vl(ctx, a, 16, mop, func);
}
+static bool gvec_xxx(DisasContext *ctx, arg_vvv *a, MemOp mop,
+ void (*func)(unsigned, uint32_t, uint32_t,
+ uint32_t, uint32_t, uint32_t))
+{
+ return gvec_vvv_vl(ctx, a, 32, mop, func);
+}
static bool gvec_vv_vl(DisasContext *ctx, arg_vv *a,
uint32_t oprsz, MemOp mop,
@@ -279,47 +285,70 @@ TRANS(vadd_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_add)
TRANS(vadd_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_add)
TRANS(vadd_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_add)
TRANS(vadd_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_add)
+TRANS(xvadd_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_add)
+TRANS(xvadd_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_add)
+TRANS(xvadd_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_add)
+TRANS(xvadd_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_add)
+
+static bool gen_vaddsub_q_vl(DisasContext *ctx, arg_vvv *a, uint32_t oprsz,
+ void (*func)(TCGv_i64, TCGv_i64, TCGv_i64,
+ TCGv_i64, TCGv_i64, TCGv_i64))
+{
+ int i;
+ TCGv_i64 rh, rl, ah, al, bh, bl;
+
+ if (!check_vec(ctx, oprsz)) {
+ return true;
+ }
-#define VADDSUB_Q(NAME) \
-static bool trans_v## NAME ##_q(DisasContext *ctx, arg_vvv *a) \
-{ \
- TCGv_i64 rh, rl, ah, al, bh, bl; \
- \
- if (!avail_LSX(ctx)) { \
- return false; \
- } \
- \
- if (!check_vec(ctx, 16)) { \
- return true; \
- } \
- \
- rh = tcg_temp_new_i64(); \
- rl = tcg_temp_new_i64(); \
- ah = tcg_temp_new_i64(); \
- al = tcg_temp_new_i64(); \
- bh = tcg_temp_new_i64(); \
- bl = tcg_temp_new_i64(); \
- \
- get_vreg64(ah, a->vj, 1); \
- get_vreg64(al, a->vj, 0); \
- get_vreg64(bh, a->vk, 1); \
- get_vreg64(bl, a->vk, 0); \
- \
- tcg_gen_## NAME ##2_i64(rl, rh, al, ah, bl, bh); \
- \
- set_vreg64(rh, a->vd, 1); \
- set_vreg64(rl, a->vd, 0); \
- \
- return true; \
-}
-
-VADDSUB_Q(add)
-VADDSUB_Q(sub)
+ rh = tcg_temp_new_i64();
+ rl = tcg_temp_new_i64();
+ ah = tcg_temp_new_i64();
+ al = tcg_temp_new_i64();
+ bh = tcg_temp_new_i64();
+ bl = tcg_temp_new_i64();
+
+ for (i = 0; i < oprsz / 16; i++) {
+ get_vreg64(ah, a->vj, 1 + i * 2);
+ get_vreg64(al, a->vj, i * 2);
+ get_vreg64(bh, a->vk, 1 + i * 2);
+ get_vreg64(bl, a->vk, i * 2);
+
+ func(rl, rh, al, ah, bl, bh);
+
+ set_vreg64(rh, a->vd, 1 + i * 2);
+ set_vreg64(rl, a->vd, i * 2);
+ }
+ return true;
+}
+
+static bool gen_vaddsub_q(DisasContext *ctx, arg_vvv *a,
+ void (*func)(TCGv_i64, TCGv_i64, TCGv_i64,
+ TCGv_i64, TCGv_i64, TCGv_i64))
+{
+ return gen_vaddsub_q_vl(ctx, a, 16, func);
+}
+
+static bool gen_xvaddsub_q(DisasContext *ctx, arg_vvv *a,
+ void (*func)(TCGv_i64, TCGv_i64, TCGv_i64,
+ TCGv_i64, TCGv_i64, TCGv_i64))
+{
+ return gen_vaddsub_q_vl(ctx, a, 32, func);
+}
TRANS(vsub_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_sub)
TRANS(vsub_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_sub)
TRANS(vsub_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_sub)
TRANS(vsub_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_sub)
+TRANS(xvsub_b, LASX, gvec_xxx, MO_8, tcg_gen_gvec_sub)
+TRANS(xvsub_h, LASX, gvec_xxx, MO_16, tcg_gen_gvec_sub)
+TRANS(xvsub_w, LASX, gvec_xxx, MO_32, tcg_gen_gvec_sub)
+TRANS(xvsub_d, LASX, gvec_xxx, MO_64, tcg_gen_gvec_sub)
+
+TRANS(vadd_q, LSX, gen_vaddsub_q, tcg_gen_add2_i64)
+TRANS(vsub_q, LSX, gen_vaddsub_q, tcg_gen_sub2_i64)
+TRANS(xvadd_q, LASX, gen_xvaddsub_q, tcg_gen_add2_i64)
+TRANS(xvsub_q, LASX, gen_xvaddsub_q, tcg_gen_sub2_i64)
TRANS(vaddi_bu, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_addi)
TRANS(vaddi_hu, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_addi)