tcg/loongarch64: Support LASX in tcg_out_vec_op

Reviewed-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2024-05-27 20:44:24 +00:00
parent 3683354664
commit 4c2c5744aa

View File

@ -1833,76 +1833,125 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
const int const_args[TCG_MAX_OP_ARGS])
{
TCGType type = vecl + TCG_TYPE_V64;
bool lasx = type == TCG_TYPE_V256;
TCGArg a0, a1, a2, a3;
static const LoongArchInsn cmp_vec_insn[16][4] = {
[TCG_COND_EQ] = {OPC_VSEQ_B, OPC_VSEQ_H, OPC_VSEQ_W, OPC_VSEQ_D},
[TCG_COND_LE] = {OPC_VSLE_B, OPC_VSLE_H, OPC_VSLE_W, OPC_VSLE_D},
[TCG_COND_LEU] = {OPC_VSLE_BU, OPC_VSLE_HU, OPC_VSLE_WU, OPC_VSLE_DU},
[TCG_COND_LT] = {OPC_VSLT_B, OPC_VSLT_H, OPC_VSLT_W, OPC_VSLT_D},
[TCG_COND_LTU] = {OPC_VSLT_BU, OPC_VSLT_HU, OPC_VSLT_WU, OPC_VSLT_DU},
};
static const LoongArchInsn cmp_vec_imm_insn[16][4] = {
[TCG_COND_EQ] = {OPC_VSEQI_B, OPC_VSEQI_H, OPC_VSEQI_W, OPC_VSEQI_D},
[TCG_COND_LE] = {OPC_VSLEI_B, OPC_VSLEI_H, OPC_VSLEI_W, OPC_VSLEI_D},
[TCG_COND_LEU] = {OPC_VSLEI_BU, OPC_VSLEI_HU, OPC_VSLEI_WU, OPC_VSLEI_DU},
[TCG_COND_LT] = {OPC_VSLTI_B, OPC_VSLTI_H, OPC_VSLTI_W, OPC_VSLTI_D},
[TCG_COND_LTU] = {OPC_VSLTI_BU, OPC_VSLTI_HU, OPC_VSLTI_WU, OPC_VSLTI_DU},
};
LoongArchInsn insn;
static const LoongArchInsn neg_vec_insn[4] = {
OPC_VNEG_B, OPC_VNEG_H, OPC_VNEG_W, OPC_VNEG_D
static const LoongArchInsn cmp_vec_insn[16][2][4] = {
[TCG_COND_EQ] = {
{ OPC_VSEQ_B, OPC_VSEQ_H, OPC_VSEQ_W, OPC_VSEQ_D },
{ OPC_XVSEQ_B, OPC_XVSEQ_H, OPC_XVSEQ_W, OPC_XVSEQ_D },
},
[TCG_COND_LE] = {
{ OPC_VSLE_B, OPC_VSLE_H, OPC_VSLE_W, OPC_VSLE_D },
{ OPC_XVSLE_B, OPC_XVSLE_H, OPC_XVSLE_W, OPC_XVSLE_D },
},
[TCG_COND_LEU] = {
{ OPC_VSLE_BU, OPC_VSLE_HU, OPC_VSLE_WU, OPC_VSLE_DU },
{ OPC_XVSLE_BU, OPC_XVSLE_HU, OPC_XVSLE_WU, OPC_XVSLE_DU },
},
[TCG_COND_LT] = {
{ OPC_VSLT_B, OPC_VSLT_H, OPC_VSLT_W, OPC_VSLT_D },
{ OPC_XVSLT_B, OPC_XVSLT_H, OPC_XVSLT_W, OPC_XVSLT_D },
},
[TCG_COND_LTU] = {
{ OPC_VSLT_BU, OPC_VSLT_HU, OPC_VSLT_WU, OPC_VSLT_DU },
{ OPC_XVSLT_BU, OPC_XVSLT_HU, OPC_XVSLT_WU, OPC_XVSLT_DU },
}
};
static const LoongArchInsn mul_vec_insn[4] = {
OPC_VMUL_B, OPC_VMUL_H, OPC_VMUL_W, OPC_VMUL_D
static const LoongArchInsn cmp_vec_imm_insn[16][2][4] = {
[TCG_COND_EQ] = {
{ OPC_VSEQI_B, OPC_VSEQI_H, OPC_VSEQI_W, OPC_VSEQI_D },
{ OPC_XVSEQI_B, OPC_XVSEQI_H, OPC_XVSEQI_W, OPC_XVSEQI_D },
},
[TCG_COND_LE] = {
{ OPC_VSLEI_B, OPC_VSLEI_H, OPC_VSLEI_W, OPC_VSLEI_D },
{ OPC_XVSLEI_B, OPC_XVSLEI_H, OPC_XVSLEI_W, OPC_XVSLEI_D },
},
[TCG_COND_LEU] = {
{ OPC_VSLEI_BU, OPC_VSLEI_HU, OPC_VSLEI_WU, OPC_VSLEI_DU },
{ OPC_XVSLEI_BU, OPC_XVSLEI_HU, OPC_XVSLEI_WU, OPC_XVSLEI_DU },
},
[TCG_COND_LT] = {
{ OPC_VSLTI_B, OPC_VSLTI_H, OPC_VSLTI_W, OPC_VSLTI_D },
{ OPC_XVSLTI_B, OPC_XVSLTI_H, OPC_XVSLTI_W, OPC_XVSLTI_D },
},
[TCG_COND_LTU] = {
{ OPC_VSLTI_BU, OPC_VSLTI_HU, OPC_VSLTI_WU, OPC_VSLTI_DU },
{ OPC_XVSLTI_BU, OPC_XVSLTI_HU, OPC_XVSLTI_WU, OPC_XVSLTI_DU },
}
};
static const LoongArchInsn smin_vec_insn[4] = {
OPC_VMIN_B, OPC_VMIN_H, OPC_VMIN_W, OPC_VMIN_D
static const LoongArchInsn neg_vec_insn[2][4] = {
{ OPC_VNEG_B, OPC_VNEG_H, OPC_VNEG_W, OPC_VNEG_D },
{ OPC_XVNEG_B, OPC_XVNEG_H, OPC_XVNEG_W, OPC_XVNEG_D },
};
static const LoongArchInsn umin_vec_insn[4] = {
OPC_VMIN_BU, OPC_VMIN_HU, OPC_VMIN_WU, OPC_VMIN_DU
static const LoongArchInsn mul_vec_insn[2][4] = {
{ OPC_VMUL_B, OPC_VMUL_H, OPC_VMUL_W, OPC_VMUL_D },
{ OPC_XVMUL_B, OPC_XVMUL_H, OPC_XVMUL_W, OPC_XVMUL_D },
};
static const LoongArchInsn smax_vec_insn[4] = {
OPC_VMAX_B, OPC_VMAX_H, OPC_VMAX_W, OPC_VMAX_D
static const LoongArchInsn smin_vec_insn[2][4] = {
{ OPC_VMIN_B, OPC_VMIN_H, OPC_VMIN_W, OPC_VMIN_D },
{ OPC_XVMIN_B, OPC_XVMIN_H, OPC_XVMIN_W, OPC_XVMIN_D },
};
static const LoongArchInsn umax_vec_insn[4] = {
OPC_VMAX_BU, OPC_VMAX_HU, OPC_VMAX_WU, OPC_VMAX_DU
static const LoongArchInsn umin_vec_insn[2][4] = {
{ OPC_VMIN_BU, OPC_VMIN_HU, OPC_VMIN_WU, OPC_VMIN_DU },
{ OPC_XVMIN_BU, OPC_XVMIN_HU, OPC_XVMIN_WU, OPC_XVMIN_DU },
};
static const LoongArchInsn ssadd_vec_insn[4] = {
OPC_VSADD_B, OPC_VSADD_H, OPC_VSADD_W, OPC_VSADD_D
static const LoongArchInsn smax_vec_insn[2][4] = {
{ OPC_VMAX_B, OPC_VMAX_H, OPC_VMAX_W, OPC_VMAX_D },
{ OPC_XVMAX_B, OPC_XVMAX_H, OPC_XVMAX_W, OPC_XVMAX_D },
};
static const LoongArchInsn usadd_vec_insn[4] = {
OPC_VSADD_BU, OPC_VSADD_HU, OPC_VSADD_WU, OPC_VSADD_DU
static const LoongArchInsn umax_vec_insn[2][4] = {
{ OPC_VMAX_BU, OPC_VMAX_HU, OPC_VMAX_WU, OPC_VMAX_DU },
{ OPC_XVMAX_BU, OPC_XVMAX_HU, OPC_XVMAX_WU, OPC_XVMAX_DU },
};
static const LoongArchInsn sssub_vec_insn[4] = {
OPC_VSSUB_B, OPC_VSSUB_H, OPC_VSSUB_W, OPC_VSSUB_D
static const LoongArchInsn ssadd_vec_insn[2][4] = {
{ OPC_VSADD_B, OPC_VSADD_H, OPC_VSADD_W, OPC_VSADD_D },
{ OPC_XVSADD_B, OPC_XVSADD_H, OPC_XVSADD_W, OPC_XVSADD_D },
};
static const LoongArchInsn ussub_vec_insn[4] = {
OPC_VSSUB_BU, OPC_VSSUB_HU, OPC_VSSUB_WU, OPC_VSSUB_DU
static const LoongArchInsn usadd_vec_insn[2][4] = {
{ OPC_VSADD_BU, OPC_VSADD_HU, OPC_VSADD_WU, OPC_VSADD_DU },
{ OPC_XVSADD_BU, OPC_XVSADD_HU, OPC_XVSADD_WU, OPC_XVSADD_DU },
};
static const LoongArchInsn shlv_vec_insn[4] = {
OPC_VSLL_B, OPC_VSLL_H, OPC_VSLL_W, OPC_VSLL_D
static const LoongArchInsn sssub_vec_insn[2][4] = {
{ OPC_VSSUB_B, OPC_VSSUB_H, OPC_VSSUB_W, OPC_VSSUB_D },
{ OPC_XVSSUB_B, OPC_XVSSUB_H, OPC_XVSSUB_W, OPC_XVSSUB_D },
};
static const LoongArchInsn shrv_vec_insn[4] = {
OPC_VSRL_B, OPC_VSRL_H, OPC_VSRL_W, OPC_VSRL_D
static const LoongArchInsn ussub_vec_insn[2][4] = {
{ OPC_VSSUB_BU, OPC_VSSUB_HU, OPC_VSSUB_WU, OPC_VSSUB_DU },
{ OPC_XVSSUB_BU, OPC_XVSSUB_HU, OPC_XVSSUB_WU, OPC_XVSSUB_DU },
};
static const LoongArchInsn sarv_vec_insn[4] = {
OPC_VSRA_B, OPC_VSRA_H, OPC_VSRA_W, OPC_VSRA_D
static const LoongArchInsn shlv_vec_insn[2][4] = {
{ OPC_VSLL_B, OPC_VSLL_H, OPC_VSLL_W, OPC_VSLL_D },
{ OPC_XVSLL_B, OPC_XVSLL_H, OPC_XVSLL_W, OPC_XVSLL_D },
};
static const LoongArchInsn shli_vec_insn[4] = {
OPC_VSLLI_B, OPC_VSLLI_H, OPC_VSLLI_W, OPC_VSLLI_D
static const LoongArchInsn shrv_vec_insn[2][4] = {
{ OPC_VSRL_B, OPC_VSRL_H, OPC_VSRL_W, OPC_VSRL_D },
{ OPC_XVSRL_B, OPC_XVSRL_H, OPC_XVSRL_W, OPC_XVSRL_D },
};
static const LoongArchInsn shri_vec_insn[4] = {
OPC_VSRLI_B, OPC_VSRLI_H, OPC_VSRLI_W, OPC_VSRLI_D
static const LoongArchInsn sarv_vec_insn[2][4] = {
{ OPC_VSRA_B, OPC_VSRA_H, OPC_VSRA_W, OPC_VSRA_D },
{ OPC_XVSRA_B, OPC_XVSRA_H, OPC_XVSRA_W, OPC_XVSRA_D },
};
static const LoongArchInsn sari_vec_insn[4] = {
OPC_VSRAI_B, OPC_VSRAI_H, OPC_VSRAI_W, OPC_VSRAI_D
static const LoongArchInsn shli_vec_insn[2][4] = {
{ OPC_VSLLI_B, OPC_VSLLI_H, OPC_VSLLI_W, OPC_VSLLI_D },
{ OPC_XVSLLI_B, OPC_XVSLLI_H, OPC_XVSLLI_W, OPC_XVSLLI_D },
};
static const LoongArchInsn rotrv_vec_insn[4] = {
OPC_VROTR_B, OPC_VROTR_H, OPC_VROTR_W, OPC_VROTR_D
static const LoongArchInsn shri_vec_insn[2][4] = {
{ OPC_VSRLI_B, OPC_VSRLI_H, OPC_VSRLI_W, OPC_VSRLI_D },
{ OPC_XVSRLI_B, OPC_XVSRLI_H, OPC_XVSRLI_W, OPC_XVSRLI_D },
};
static const LoongArchInsn rotri_vec_insn[4] = {
OPC_VROTRI_B, OPC_VROTRI_H, OPC_VROTRI_W, OPC_VROTRI_D
static const LoongArchInsn sari_vec_insn[2][4] = {
{ OPC_VSRAI_B, OPC_VSRAI_H, OPC_VSRAI_W, OPC_VSRAI_D },
{ OPC_XVSRAI_B, OPC_XVSRAI_H, OPC_XVSRAI_W, OPC_XVSRAI_D },
};
static const LoongArchInsn rotrv_vec_insn[2][4] = {
{ OPC_VROTR_B, OPC_VROTR_H, OPC_VROTR_W, OPC_VROTR_D },
{ OPC_XVROTR_B, OPC_XVROTR_H, OPC_XVROTR_W, OPC_XVROTR_D },
};
static const LoongArchInsn rotri_vec_insn[2][4] = {
{ OPC_VROTRI_B, OPC_VROTRI_H, OPC_VROTRI_W, OPC_VROTRI_D },
{ OPC_XVROTRI_B, OPC_XVROTRI_H, OPC_XVROTRI_W, OPC_XVROTRI_D },
};
a0 = args[0];
@ -1910,9 +1959,6 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
a2 = args[2];
a3 = args[3];
/* Currently only supports V64 & V128 */
tcg_debug_assert(type == TCG_TYPE_V64 || type == TCG_TYPE_V128);
switch (opc) {
case INDEX_op_st_vec:
tcg_out_st(s, type, a0, a1, a2);
@ -1921,7 +1967,7 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
tcg_out_ld(s, type, a0, a1, a2);
break;
case INDEX_op_and_vec:
insn = OPC_VAND_V;
insn = lasx ? OPC_XVAND_V : OPC_VAND_V;
goto vdvjvk;
case INDEX_op_andc_vec:
/*
@ -1931,22 +1977,22 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
*/
a1 = a2;
a2 = args[1];
insn = OPC_VANDN_V;
insn = lasx ? OPC_XVANDN_V : OPC_VANDN_V;
goto vdvjvk;
case INDEX_op_or_vec:
insn = OPC_VOR_V;
insn = lasx ? OPC_XVOR_V : OPC_VOR_V;
goto vdvjvk;
case INDEX_op_orc_vec:
insn = OPC_VORN_V;
insn = lasx ? OPC_XVORN_V : OPC_VORN_V;
goto vdvjvk;
case INDEX_op_xor_vec:
insn = OPC_VXOR_V;
insn = lasx ? OPC_XVXOR_V : OPC_VXOR_V;
goto vdvjvk;
case INDEX_op_not_vec:
a2 = a1;
/* fall through */
case INDEX_op_nor_vec:
insn = OPC_VNOR_V;
insn = lasx ? OPC_XVNOR_V : OPC_VNOR_V;
goto vdvjvk;
case INDEX_op_cmp_vec:
{
@ -1962,13 +2008,13 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
cond == TCG_COND_LE ||
cond == TCG_COND_LT) &&
(-0x10 <= value && value <= 0x0f)) {
insn = cmp_vec_imm_insn[cond][vece];
insn = cmp_vec_imm_insn[cond][lasx][vece];
tcg_out32(s, encode_vdvjsk5_insn(insn, a0, a1, value));
break;
} else if ((cond == TCG_COND_LEU ||
cond == TCG_COND_LTU) &&
(0x00 <= value && value <= 0x1f)) {
insn = cmp_vec_imm_insn[cond][vece];
insn = cmp_vec_imm_insn[cond][lasx][vece];
tcg_out32(s, encode_vdvjuk5_insn(insn, a0, a1, value));
break;
}
@ -1982,86 +2028,91 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
a2 = TCG_VEC_TMP0;
}
insn = cmp_vec_insn[cond][vece];
insn = cmp_vec_insn[cond][lasx][vece];
if (insn == 0) {
TCGArg t;
t = a1, a1 = a2, a2 = t;
cond = tcg_swap_cond(cond);
insn = cmp_vec_insn[cond][vece];
insn = cmp_vec_insn[cond][lasx][vece];
tcg_debug_assert(insn != 0);
}
}
goto vdvjvk;
case INDEX_op_add_vec:
tcg_out_addsub_vec(s, false, vece, a0, a1, a2, const_args[2], true);
tcg_out_addsub_vec(s, lasx, vece, a0, a1, a2, const_args[2], true);
break;
case INDEX_op_sub_vec:
tcg_out_addsub_vec(s, false, vece, a0, a1, a2, const_args[2], false);
tcg_out_addsub_vec(s, lasx, vece, a0, a1, a2, const_args[2], false);
break;
case INDEX_op_neg_vec:
tcg_out32(s, encode_vdvj_insn(neg_vec_insn[vece], a0, a1));
tcg_out32(s, encode_vdvj_insn(neg_vec_insn[lasx][vece], a0, a1));
break;
case INDEX_op_mul_vec:
insn = mul_vec_insn[vece];
insn = mul_vec_insn[lasx][vece];
goto vdvjvk;
case INDEX_op_smin_vec:
insn = smin_vec_insn[vece];
insn = smin_vec_insn[lasx][vece];
goto vdvjvk;
case INDEX_op_smax_vec:
insn = smax_vec_insn[vece];
insn = smax_vec_insn[lasx][vece];
goto vdvjvk;
case INDEX_op_umin_vec:
insn = umin_vec_insn[vece];
insn = umin_vec_insn[lasx][vece];
goto vdvjvk;
case INDEX_op_umax_vec:
insn = umax_vec_insn[vece];
insn = umax_vec_insn[lasx][vece];
goto vdvjvk;
case INDEX_op_ssadd_vec:
insn = ssadd_vec_insn[vece];
insn = ssadd_vec_insn[lasx][vece];
goto vdvjvk;
case INDEX_op_usadd_vec:
insn = usadd_vec_insn[vece];
insn = usadd_vec_insn[lasx][vece];
goto vdvjvk;
case INDEX_op_sssub_vec:
insn = sssub_vec_insn[vece];
insn = sssub_vec_insn[lasx][vece];
goto vdvjvk;
case INDEX_op_ussub_vec:
insn = ussub_vec_insn[vece];
insn = ussub_vec_insn[lasx][vece];
goto vdvjvk;
case INDEX_op_shlv_vec:
insn = shlv_vec_insn[vece];
insn = shlv_vec_insn[lasx][vece];
goto vdvjvk;
case INDEX_op_shrv_vec:
insn = shrv_vec_insn[vece];
insn = shrv_vec_insn[lasx][vece];
goto vdvjvk;
case INDEX_op_sarv_vec:
insn = sarv_vec_insn[vece];
insn = sarv_vec_insn[lasx][vece];
goto vdvjvk;
case INDEX_op_rotlv_vec:
/* rotlv_vec a1, a2 = rotrv_vec a1, -a2 */
tcg_out32(s, encode_vdvj_insn(neg_vec_insn[vece], TCG_VEC_TMP0, a2));
tcg_out32(s, encode_vdvj_insn(neg_vec_insn[lasx][vece],
TCG_VEC_TMP0, a2));
a2 = TCG_VEC_TMP0;
/* fall through */
case INDEX_op_rotrv_vec:
insn = rotrv_vec_insn[vece];
insn = rotrv_vec_insn[lasx][vece];
goto vdvjvk;
case INDEX_op_shli_vec:
insn = shli_vec_insn[vece];
insn = shli_vec_insn[lasx][vece];
goto vdvjukN;
case INDEX_op_shri_vec:
insn = shri_vec_insn[vece];
insn = shri_vec_insn[lasx][vece];
goto vdvjukN;
case INDEX_op_sari_vec:
insn = sari_vec_insn[vece];
insn = sari_vec_insn[lasx][vece];
goto vdvjukN;
case INDEX_op_rotli_vec:
/* rotli_vec a1, a2 = rotri_vec a1, -a2 */
a2 = extract32(-a2, 0, 3 + vece);
insn = rotri_vec_insn[vece];
insn = rotri_vec_insn[lasx][vece];
goto vdvjukN;
case INDEX_op_bitsel_vec:
/* vbitsel vd, vj, vk, va = bitsel_vec vd, va, vk, vj */
tcg_out_opc_vbitsel_v(s, a0, a3, a2, a1);
if (lasx) {
tcg_out_opc_xvbitsel_v(s, a0, a3, a2, a1);
} else {
tcg_out_opc_vbitsel_v(s, a0, a3, a2, a1);
}
break;
case INDEX_op_dupm_vec:
tcg_out_dupm_vec(s, type, vece, a0, a1, a2);