target/loongarch: Implement xvadd/xvsub

This patch includes:
- XVADD.{B/H/W/D/Q};
- XVSUB.{B/H/W/D/Q}.

Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20230914022645.1151356-15-gaosong@loongson.cn>
This commit is contained in:
Song Gao 2023-09-14 10:26:02 +08:00
parent cf61aef308
commit 269ca39a7d
No known key found for this signature in database
GPG Key ID: 40A2FFF239263EDF
4 changed files with 107 additions and 37 deletions

View File

@ -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)

View File

@ -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)
#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; \
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;
}
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;
}
VADDSUB_Q(add)
VADDSUB_Q(sub)
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)

View File

@ -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

View File

@ -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;