From 88ea28d5d4144a227f2d572f0b6d593a2e0beefb Mon Sep 17 00:00:00 2001 From: Lu Zeng Date: Wed, 2 Sep 2026 18:07:24 +0800 Subject: [PATCH 1/6] LATX, AVX: write packed conversions directly to the destination Signed-off-by: Lu Zeng --- target/i386/latx/translator/tr-avx-cvt.c | 76 ++++++++++++++++-------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/target/i386/latx/translator/tr-avx-cvt.c b/target/i386/latx/translator/tr-avx-cvt.c index e903ceeddd..e937da6b1e 100644 --- a/target/i386/latx/translator/tr-avx-cvt.c +++ b/target/i386/latx/translator/tr-avx-cvt.c @@ -102,26 +102,38 @@ static bool translate_vcvtps2dq_opt(IR1_INST * pir1) { IR2_OPND dest = load_freg256_from_ir1(opnd0); IR2_OPND src = load_freg256_from_ir1(opnd1); - IR2_OPND temp_f = ra_alloc_ftemp(); IR2_OPND sse_invalid = ra_alloc_ftemp(); IR2_OPND overflow = ra_alloc_ftemp(); IR2_OPND comp_mask = ra_alloc_ftemp(); + bool same_reg = ir1_opnd_is_same_reg(opnd0, opnd1); if (ir1_opnd_is_xmm(opnd0)) { - la_vftint_w_s(temp_f, src); - la_vldi(sse_invalid, 0b1001110000000); // broadcast 0x80000000 to all 0x1380 - la_vldi(overflow, (0b10011 << 8) | 0x4f); //0x134f - la_vfcmp_cond_s(comp_mask, overflow, src, 0xE); // get Nan mark 0xE=cULE - la_vbitsel_v(temp_f, temp_f, sse_invalid, comp_mask); - la_vand_v(dest, temp_f, temp_f); + if (same_reg) { + la_vldi(sse_invalid, 0b1001110000000); + la_vldi(overflow, (0b10011 << 8) | 0x4f); + la_vfcmp_cond_s(comp_mask, overflow, src, 0xE); + la_vftint_w_s(dest, src); + } else { + la_vftint_w_s(dest, src); + la_vldi(sse_invalid, 0b1001110000000); + la_vldi(overflow, (0b10011 << 8) | 0x4f); + la_vfcmp_cond_s(comp_mask, overflow, src, 0xE); + } + la_vbitsel_v(dest, dest, sse_invalid, comp_mask); set_high128_xreg_to_zero(dest); } else { - la_xvftint_w_s(temp_f, src); - la_xvldi(sse_invalid, 0b1001110000000); // broadcast 0x80000000 to all 0x1380 - la_xvldi(overflow, (0b10011 << 8) | 0x4f); //0x134f - la_xvfcmp_cond_s(comp_mask, overflow, src, 0xE); // get Nan mark 0xE=cULE - la_xvbitsel_v(temp_f, temp_f, sse_invalid, comp_mask); - la_xvand_v(dest, temp_f, temp_f); + if (same_reg) { + la_xvldi(sse_invalid, 0b1001110000000); + la_xvldi(overflow, (0b10011 << 8) | 0x4f); + la_xvfcmp_cond_s(comp_mask, overflow, src, 0xE); + la_xvftint_w_s(dest, src); + } else { + la_xvftint_w_s(dest, src); + la_xvldi(sse_invalid, 0b1001110000000); + la_xvldi(overflow, (0b10011 << 8) | 0x4f); + la_xvfcmp_cond_s(comp_mask, overflow, src, 0xE); + } + la_xvbitsel_v(dest, dest, sse_invalid, comp_mask); } return true; } @@ -829,26 +841,38 @@ static bool translate_vcvttps2dq_opt(IR1_INST * pir1) { IR2_OPND dest = load_freg256_from_ir1(opnd0); IR2_OPND src = load_freg256_from_ir1(opnd1); - IR2_OPND temp_f = ra_alloc_ftemp(); IR2_OPND sse_invalid = ra_alloc_ftemp(); IR2_OPND overflow = ra_alloc_ftemp(); IR2_OPND comp_mask = ra_alloc_ftemp(); + bool same_reg = ir1_opnd_is_same_reg(opnd0, opnd1); if (ir1_opnd_is_xmm(opnd0)) { - la_vftintrz_w_s(temp_f, src); - la_vldi(sse_invalid, 0b1001110000000); // broadcast 0x80000000 to all 0x1380 - la_vldi(overflow, (0b10011 << 8) | 0x4f); //0x134f 2^31 - la_vfcmp_cond_s(comp_mask, overflow, src, 0xE); // get Nan mark 0xE=cULE - la_vbitsel_v(temp_f, temp_f, sse_invalid, comp_mask); - la_vand_v(dest, temp_f, temp_f); + if (same_reg) { + la_vldi(sse_invalid, 0b1001110000000); + la_vldi(overflow, (0b10011 << 8) | 0x4f); + la_vfcmp_cond_s(comp_mask, overflow, src, 0xE); + la_vftintrz_w_s(dest, src); + } else { + la_vftintrz_w_s(dest, src); + la_vldi(sse_invalid, 0b1001110000000); + la_vldi(overflow, (0b10011 << 8) | 0x4f); + la_vfcmp_cond_s(comp_mask, overflow, src, 0xE); + } + la_vbitsel_v(dest, dest, sse_invalid, comp_mask); set_high128_xreg_to_zero(dest); } else { - la_xvftintrz_w_s(temp_f, src); - la_xvldi(sse_invalid, 0b1001110000000); // broadcast 0x80000000 to all 0x1380 - la_xvldi(overflow, (0b10011 << 8) | 0x4f); //0x134f 2^31 - la_xvfcmp_cond_s(comp_mask, overflow, src, 0xE); // get Nan mark 0xE=cULE - la_xvbitsel_v(temp_f, temp_f, sse_invalid, comp_mask); - la_xvand_v(dest, temp_f, temp_f); + if (same_reg) { + la_xvldi(sse_invalid, 0b1001110000000); + la_xvldi(overflow, (0b10011 << 8) | 0x4f); + la_xvfcmp_cond_s(comp_mask, overflow, src, 0xE); + la_xvftintrz_w_s(dest, src); + } else { + la_xvftintrz_w_s(dest, src); + la_xvldi(sse_invalid, 0b1001110000000); + la_xvldi(overflow, (0b10011 << 8) | 0x4f); + la_xvfcmp_cond_s(comp_mask, overflow, src, 0xE); + } + la_xvbitsel_v(dest, dest, sse_invalid, comp_mask); } return true; } From c0ff1ef780c574eb14acf7f35273c39bebc658f3 Mon Sep 17 00:00:00 2001 From: Lu Zeng Date: Wed, 2 Sep 2026 18:08:24 +0800 Subject: [PATCH 2/6] LATX, AVX: streamline integer narrowing and rounded multiply Signed-off-by: Lu Zeng --- target/i386/latx/translator/tr-avx.c | 77 ++++++++++++---------------- 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/target/i386/latx/translator/tr-avx.c b/target/i386/latx/translator/tr-avx.c index 7c809154e5..b54e951e0c 100644 --- a/target/i386/latx/translator/tr-avx.c +++ b/target/i386/latx/translator/tr-avx.c @@ -1702,41 +1702,42 @@ bool translate_vpackusxx(IR1_INST * pir1) { IR2_OPND dest = load_freg256_from_ir1(opnd0); IR2_OPND src1 = load_freg256_from_ir1(opnd1); IR2_OPND src2 = load_freg256_from_ir1(opnd2); - IR2_OPND temp1 = ra_alloc_ftemp(); IR2_OPND temp2; + bool dest_is_src2 = (ir1_opnd_is_xmm(opnd2) || + ir1_opnd_is_ymm(opnd2)) && + ir1_opnd_base_reg_num(opnd0) == + ir1_opnd_base_reg_num(opnd2); IR1_OPCODE op = ir1_opcode(pir1); - IR2_INST * ( * cmp_inst)(IR2_OPND, IR2_OPND, int); IR2_INST * ( * cvt_inst)(IR2_OPND, IR2_OPND, int); switch (op) { case dt_X86_INS_VPACKUSDW: - cmp_inst = la_xvslti_w; cvt_inst = la_xvssrani_hu_w; break; case dt_X86_INS_VPACKUSWB: - cmp_inst = la_xvslti_h; cvt_inst = la_xvssrani_bu_h; break; default: - cmp_inst = NULL; cvt_inst = NULL; lsassert(0); break; } - cmp_inst(temp1, src1, 0); - la_xvandn_v(temp1, temp1, src1); - if ((ir1_opnd_is_xmm(opnd2) || ir1_opnd_is_ymm(opnd2)) && + if (dest_is_src2) { + temp2 = dest; + } else if ((ir1_opnd_is_xmm(opnd2) || ir1_opnd_is_ymm(opnd2)) && ir1_opnd_base_reg_num(opnd1) == ir1_opnd_base_reg_num(opnd2)) { - temp2 = temp1; + temp2 = ra_alloc_ftemp(); + la_xvori_b(temp2, src2, 0); } else { temp2 = ra_alloc_ftemp(); - cmp_inst(temp2, src2, 0); - la_xvandn_v(temp2, temp2, src2); + la_xvori_b(temp2, src2, 0); } - cvt_inst(temp2, temp1, 0); + cvt_inst(temp2, src1, 0); if (ir1_opnd_is_xmm(opnd0)) { set_high128_xreg_to_zero(temp2); } - la_xvori_b(dest, temp2, 0); + if (!dest_is_src2) { + la_xvori_b(dest, temp2, 0); + } return true; } @@ -4606,22 +4607,10 @@ bool translate_vpmulhrsw(IR1_INST * pir1) { IR2_OPND src2 = load_freg128_from_ir1(opnd2); IR2_OPND temp1 = ra_alloc_ftemp(); IR2_OPND temp2 = ra_alloc_ftemp(); - IR2_OPND temp3 = ra_alloc_ftemp(); la_vmulwev_w_h(temp1, src1, src2); la_vmulwod_w_h(temp2, src1, src2); - - la_vsrai_w(temp1, temp1, 0xe); - la_vsrai_w(temp2, temp2, 0xe); - - la_vandi_b(temp3, temp3, 0x0); - la_vbitseti_w(temp3, temp3, 0); - - la_vadd_w(temp1, temp1, temp3); - la_vadd_w(temp2, temp2, temp3); - - la_vsrai_w(temp1, temp1, 0x1); - la_vsrai_w(temp2, temp2, 0x1); - + la_vsrari_w(temp1, temp1, 15); + la_vsrari_w(temp2, temp2, 15); la_vpackev_h(dest, temp2, temp1); set_high128_xreg_to_zero(dest); @@ -4632,22 +4621,10 @@ bool translate_vpmulhrsw(IR1_INST * pir1) { IR2_OPND src2 = load_freg256_from_ir1(opnd2); IR2_OPND temp1 = ra_alloc_ftemp(); IR2_OPND temp2 = ra_alloc_ftemp(); - IR2_OPND temp3 = ra_alloc_ftemp(); la_xvmulwev_w_h(temp1, src1, src2); la_xvmulwod_w_h(temp2, src1, src2); - - la_xvsrai_w(temp1, temp1, 0xe); - la_xvsrai_w(temp2, temp2, 0xe); - - la_xvandi_b(temp3, temp3, 0x0); - la_xvbitseti_w(temp3, temp3, 0); - - la_xvadd_w(temp1, temp1, temp3); - la_xvadd_w(temp2, temp2, temp3); - - la_xvsrai_w(temp1, temp1, 0x1); - la_xvsrai_w(temp2, temp2, 0x1); - + la_xvsrari_w(temp1, temp1, 15); + la_xvsrari_w(temp2, temp2, 15); la_xvpackev_h(dest, temp2, temp1); } @@ -4805,6 +4782,12 @@ bool translate_vpackssxx(IR1_INST * pir1) { IR2_OPND src1 = load_freg256_from_ir1(opnd1); IR2_OPND src2 = load_freg256_from_ir1(opnd2); IR2_OPND temp; + bool dest_is_src1 = ir1_opnd_base_reg_num(opnd0) == + ir1_opnd_base_reg_num(opnd1); + bool dest_is_src2 = (ir1_opnd_is_xmm(opnd2) || + ir1_opnd_is_ymm(opnd2)) && + ir1_opnd_base_reg_num(opnd0) == + ir1_opnd_base_reg_num(opnd2); IR2_INST * ( * cvt_inst)(IR2_OPND, IR2_OPND, int); switch (ir1_opcode(pir1)) { case dt_X86_INS_VPACKSSDW: @@ -4818,9 +4801,15 @@ bool translate_vpackssxx(IR1_INST * pir1) { lsassert(0); break; } - if (ir1_opnd_is_xmm(opnd2) || ir1_opnd_is_ymm(opnd2)) { + if (dest_is_src2) { + temp = dest; + } else if ((ir1_opnd_is_xmm(opnd2) || ir1_opnd_is_ymm(opnd2)) && + dest_is_src1) { temp = ra_alloc_ftemp(); la_xvori_b(temp, src2, 0); + } else if (ir1_opnd_is_xmm(opnd2) || ir1_opnd_is_ymm(opnd2)) { + temp = dest; + la_xvori_b(temp, src2, 0); } else { temp = src2; } @@ -4828,7 +4817,9 @@ bool translate_vpackssxx(IR1_INST * pir1) { if (ir1_opnd_is_xmm(opnd0)) { set_high128_xreg_to_zero(temp); } - la_xvori_b(dest, temp, 0); + if (temp._reg_num != dest._reg_num) { + la_xvori_b(dest, temp, 0); + } return true; } From 4a7274d9eebdcd1a38c89b225f849add247b5232 Mon Sep 17 00:00:00 2001 From: Lu Zeng Date: Wed, 2 Sep 2026 18:10:26 +0800 Subject: [PATCH 3/6] LATX, AVX: avoid redundant vector copies and lane inserts Signed-off-by: Lu Zeng --- target/i386/latx/translator/tr-avx.c | 35 +++++++++++++++------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/target/i386/latx/translator/tr-avx.c b/target/i386/latx/translator/tr-avx.c index b54e951e0c..9759bbdce1 100644 --- a/target/i386/latx/translator/tr-avx.c +++ b/target/i386/latx/translator/tr-avx.c @@ -1272,14 +1272,12 @@ bool translate_vextractf128(IR1_INST * pir1) { uint8 imm = ir1_opnd_uimm(ir1_get_opnd(pir1, 2)) & 0x1; if (ir1_opnd_is_xmm(ir1_get_opnd(pir1, 0))) { IR2_OPND dest = load_freg128_from_ir1(ir1_get_opnd(pir1, 0)); - IR2_OPND temp = ra_alloc_ftemp(); if (!imm) { - la_xvpermi_q(temp, src, VEXTRINS_IMM_4_0(3, 0)); + la_xvpermi_q(dest, src, VEXTRINS_IMM_4_0(3, 0)); } else { - la_xvpermi_q(temp, src, VEXTRINS_IMM_4_0(3, 1)); + la_xvpermi_q(dest, src, VEXTRINS_IMM_4_0(3, 1)); } - set_high128_xreg_to_zero(temp); - la_xvori_b(dest, temp, 0); + set_high128_xreg_to_zero(dest); } else { if (!imm) { store_freg128_to_ir1_mem(src, ir1_get_opnd(pir1, 0)); @@ -1374,14 +1372,25 @@ bool translate_vinserti128(IR1_INST * pir1) { IR2_OPND src1 = load_freg256_from_ir1(ir1_get_opnd(pir1, 1)); IR2_OPND src2 = load_freg128_from_ir1(ir1_get_opnd(pir1, 2)); uint8 imm = ir1_opnd_uimm(ir1_get_opnd(pir1, 3)) & 0x1; - IR2_OPND temp = ra_alloc_ftemp(); - la_xvori_b(temp, src1, 0); + bool dest_is_src1 = ir1_opnd_base_reg_num(ir1_get_opnd(pir1, 0)) == + ir1_opnd_base_reg_num(ir1_get_opnd(pir1, 1)); + bool dest_is_src2 = ir1_opnd_is_xmm(ir1_get_opnd(pir1, 2)) && + ir1_opnd_base_reg_num(ir1_get_opnd(pir1, 0)) == + ir1_opnd_base_reg_num(ir1_get_opnd(pir1, 2)); + IR2_OPND result = dest_is_src2 && !dest_is_src1 ? + ra_alloc_ftemp() : dest; + + if (!dest_is_src1) { + la_xvori_b(result, src1, 0); + } if (!imm) { - la_xvpermi_q(temp, src2, VEXTRINS_IMM_4_0(3, 0)); + la_xvpermi_q(result, src2, VEXTRINS_IMM_4_0(3, 0)); } else { - la_xvpermi_q(temp, src2, VEXTRINS_IMM_4_0(0, 2)); + la_xvpermi_q(result, src2, VEXTRINS_IMM_4_0(0, 2)); + } + if (dest_is_src2 && !dest_is_src1) { + la_xvori_b(dest, result, 0); } - la_xvori_b(dest, temp, 0); return true; } @@ -3496,8 +3505,6 @@ bool translate_vpbroadcastd(IR1_INST *pir1) la_xvreplve0_w(dest, src); } else if (ir1_opnd_is_ymm(opnd0)) { la_xvreplve0_w(dest, src); - la_xvinsve0_d(dest, dest, 2); - la_xvinsve0_d(dest, dest, 3); } else { lsassert(0); } @@ -6458,8 +6465,6 @@ bool translate_vpbroadcastb(IR1_INST *pir1) la_xvreplve0_b(dest, src); } else if (ir1_opnd_is_ymm(opnd0)) { la_xvreplve0_b(dest, src); - la_xvinsve0_d(dest, dest, 2); - la_xvinsve0_d(dest, dest, 3); } else { lsassert(0); } @@ -6494,8 +6499,6 @@ bool translate_vpbroadcastw(IR1_INST *pir1) la_xvreplve0_h(dest, src); } else if (ir1_opnd_is_ymm(opnd0)) { la_xvreplve0_h(dest, src); - la_xvinsve0_d(dest, dest, 2); - la_xvinsve0_d(dest, dest, 3); } else { lsassert(0); } From e047fb7abd038e8ffabf90d465d67a8221d1d779 Mon Sep 17 00:00:00 2001 From: Lu Zeng Date: Wed, 2 Sep 2026 18:26:20 +0800 Subject: [PATCH 4/6] LATX, AVX: write VPBLENDVB directly to the destination Signed-off-by: Lu Zeng --- target/i386/latx/translator/tr-avx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target/i386/latx/translator/tr-avx.c b/target/i386/latx/translator/tr-avx.c index 9759bbdce1..6ab3f0bcf5 100644 --- a/target/i386/latx/translator/tr-avx.c +++ b/target/i386/latx/translator/tr-avx.c @@ -1939,15 +1939,15 @@ bool translate_vpblendvb(IR1_INST * pir1) { (ir1_opnd_is_ymm(opnd0) && ir1_opnd_is_ymm(opnd1))); IR2_OPND dest, src1, src2, src3; IR2_OPND temp = ra_alloc_ftemp(); - dest = load_freg256_from_ir1(opnd0); + dest = ra_alloc_xmm(ir1_opnd_base_reg_num(opnd0)); src1 = load_freg256_from_ir1(opnd1); src2 = load_freg256_from_ir1(opnd2); src3 = load_freg256_from_ir1(opnd3); la_xvslti_b(temp, src3, 0); - la_xvbitsel_v(temp, src1, src2, temp); - if (ir1_opnd_is_xmm(opnd0)) - set_high128_xreg_to_zero(temp); - la_xvori_b(dest, temp, 0); + la_xvbitsel_v(dest, src1, src2, temp); + if (ir1_opnd_is_xmm(opnd0)) { + set_high128_xreg_to_zero(dest); + } return true; } From 361848da1f0d2510b323574bf098494c06c35c5b Mon Sep 17 00:00:00 2001 From: Lu Zeng Date: Wed, 2 Sep 2026 18:36:16 +0800 Subject: [PATCH 5/6] LATX, AVX: use direct widening multiply-add sequences Signed-off-by: Lu Zeng --- target/i386/latx/translator/tr-avx-lsx.c | 53 ++++++-------- target/i386/latx/translator/tr-avx.c | 91 +++++++++--------------- 2 files changed, 56 insertions(+), 88 deletions(-) diff --git a/target/i386/latx/translator/tr-avx-lsx.c b/target/i386/latx/translator/tr-avx-lsx.c index 10d8342950..5ac247a882 100644 --- a/target/i386/latx/translator/tr-avx-lsx.c +++ b/target/i386/latx/translator/tr-avx-lsx.c @@ -605,46 +605,35 @@ static bool translate_avx_integer_3op_custom_lsx( static void translate_vpmaddwd_lane_lsx(IR2_OPND dest, IR2_OPND src1, IR2_OPND src2) { - IR2_OPND temp = ra_alloc_ftemp(); + if (dest._reg_num != src1._reg_num && + dest._reg_num != src2._reg_num) { + la_vmulwev_w_h(dest, src1, src2); + la_vmaddwod_w_h(dest, src1, src2); + return; + } - la_vxor_v(temp, temp, temp); - la_vmaddwev_w_h(temp, src1, src2); - la_vmaddwod_w_h(temp, src1, src2); - la_vbsll_v(dest, temp, 0); - ra_free_temp(temp); + IR2_OPND even = ra_alloc_ftemp(); + IR2_OPND odd = ra_alloc_ftemp(); + + la_vmulwev_w_h(even, src1, src2); + la_vmulwod_w_h(odd, src1, src2); + la_vadd_w(dest, even, odd); + ra_free_temp(odd); + ra_free_temp(even); } static void translate_vpmaddubsw_lane_lsx(IR2_OPND dest, IR2_OPND src1, IR2_OPND src2) { - IR2_OPND temp1 = ra_alloc_ftemp(); - IR2_OPND temp2 = ra_alloc_ftemp(); - IR2_OPND temp3 = ra_alloc_ftemp(); - IR2_OPND temp4 = ra_alloc_ftemp(); - IR2_OPND temp5 = ra_alloc_ftemp(); - IR2_OPND one = ra_alloc_itemp(); + IR2_OPND even = ra_alloc_ftemp(); + IR2_OPND odd = ra_alloc_ftemp(); /* Unsigned src1 multiplied by signed src2, then saturated to halfwords. */ - la_vreplgr2vr_d(temp1, zero_ir2_opnd); - la_vabsd_b(temp3, src2, temp1); - la_vmaddwev_h_bu(temp1, src1, temp3); - la_vreplgr2vr_d(temp2, zero_ir2_opnd); - la_vmaddwod_h_bu(temp2, src1, temp3); - - la_ori(one, zero_ir2_opnd, 1); - la_vreplgr2vr_b(temp3, one); - la_vsigncov_b(temp4, src2, temp3); - la_vmulwev_h_b(temp5, temp4, temp3); - la_vmulwod_h_b(temp3, temp4, temp3); - la_vmul_h(temp1, temp1, temp5); - la_vmul_h(temp2, temp2, temp3); - la_vsadd_h(dest, temp2, temp1); - ra_free_temp(one); - ra_free_temp(temp5); - ra_free_temp(temp4); - ra_free_temp(temp3); - ra_free_temp(temp2); - ra_free_temp(temp1); + la_vmulwev_h_bu_b(even, src1, src2); + la_vmulwod_h_bu_b(odd, src1, src2); + la_vsadd_h(dest, even, odd); + ra_free_temp(odd); + ra_free_temp(even); } static void translate_vpmulhrsw_lane_lsx(IR2_OPND dest, IR2_OPND src1, diff --git a/target/i386/latx/translator/tr-avx.c b/target/i386/latx/translator/tr-avx.c index 6ab3f0bcf5..16b6fe0546 100644 --- a/target/i386/latx/translator/tr-avx.c +++ b/target/i386/latx/translator/tr-avx.c @@ -3762,23 +3762,35 @@ bool translate_vpmaddwd(IR1_INST * pir1) { IR2_OPND dest = load_freg128_from_ir1(opnd0); IR2_OPND src1 = load_freg128_from_ir1(opnd1); IR2_OPND src2 = load_freg128_from_ir1(opnd2); - IR2_OPND temp = ra_alloc_ftemp(); + if (dest._reg_num != src1._reg_num && + dest._reg_num != src2._reg_num) { + la_vmulwev_w_h(dest, src1, src2); + la_vmaddwod_w_h(dest, src1, src2); + } else { + IR2_OPND even = ra_alloc_ftemp(); + IR2_OPND odd = ra_alloc_ftemp(); - la_vxor_v(temp, temp, temp); - la_vmaddwev_w_h(temp, src1, src2); - la_vmaddwod_w_h(temp, src1, src2); - la_vbsll_v(dest, temp, 0); + la_vmulwev_w_h(even, src1, src2); + la_vmulwod_w_h(odd, src1, src2); + la_vadd_w(dest, even, odd); + } set_high128_xreg_to_zero(dest); } else { IR2_OPND dest = load_freg256_from_ir1(opnd0); IR2_OPND src1 = load_freg256_from_ir1(opnd1); IR2_OPND src2 = load_freg256_from_ir1(opnd2); - IR2_OPND temp = ra_alloc_ftemp(); + if (dest._reg_num != src1._reg_num && + dest._reg_num != src2._reg_num) { + la_xvmulwev_w_h(dest, src1, src2); + la_xvmaddwod_w_h(dest, src1, src2); + } else { + IR2_OPND even = ra_alloc_ftemp(); + IR2_OPND odd = ra_alloc_ftemp(); - la_xvxor_v(temp, temp, temp); - la_xvmaddwev_w_h(temp, src1, src2); - la_xvmaddwod_w_h(temp, src1, src2); - la_xvbsll_v(dest, temp, 0); + la_xvmulwev_w_h(even, src1, src2); + la_xvmulwod_w_h(odd, src1, src2); + la_xvadd_w(dest, even, odd); + } } return true; } @@ -3796,29 +3808,13 @@ bool translate_vpmaddubsw(IR1_INST * pir1) { IR2_OPND src1 = load_freg128_from_ir1(opnd1); IR2_OPND src2 = load_freg128_from_ir1(opnd2); - IR2_OPND temp1 = ra_alloc_ftemp(); - IR2_OPND temp2 = ra_alloc_ftemp(); - IR2_OPND temp3 = ra_alloc_ftemp(); - IR2_OPND temp4 = ra_alloc_ftemp(); - IR2_OPND temp5 = ra_alloc_ftemp(); - IR2_OPND itmp = ra_alloc_itemp(); - /* unsigned src1 * signed src2 */ - la_vreplgr2vr_d(temp1, zero_ir2_opnd); - la_vabsd_b(temp3, src2, temp1); - la_vmaddwev_h_bu(temp1, src1, temp3); - la_vreplgr2vr_d(temp2, zero_ir2_opnd); - la_vmaddwod_h_bu(temp2, src1, temp3); - - la_ori(itmp, zero_ir2_opnd, 0x1); - la_vreplgr2vr_b(temp3, itmp); - la_vsigncov_b(temp4, src2, temp3); - - la_vmulwev_h_b(temp5, temp4, temp3); - la_vmulwod_h_b(temp3, temp4, temp3); - - la_vmul_h(temp1, temp1, temp5); - la_vmul_h(temp2, temp2, temp3); - la_vsadd_h(dest, temp2, temp1); + IR2_OPND even = ra_alloc_ftemp(); + IR2_OPND odd = ra_alloc_ftemp(); + + /* Unsigned src1 bytes times signed src2 bytes, pairwise saturated. */ + la_vmulwev_h_bu_b(even, src1, src2); + la_vmulwod_h_bu_b(odd, src1, src2); + la_vsadd_h(dest, even, odd); set_high128_xreg_to_zero(dest); @@ -3826,29 +3822,12 @@ bool translate_vpmaddubsw(IR1_INST * pir1) { IR2_OPND dest = load_freg256_from_ir1(opnd0); IR2_OPND src1 = load_freg256_from_ir1(opnd1); IR2_OPND src2 = load_freg256_from_ir1(opnd2); - IR2_OPND temp1 = ra_alloc_ftemp(); - IR2_OPND temp2 = ra_alloc_ftemp(); - IR2_OPND temp3 = ra_alloc_ftemp(); - IR2_OPND temp4 = ra_alloc_ftemp(); - IR2_OPND temp5 = ra_alloc_ftemp(); - IR2_OPND itmp = ra_alloc_itemp(); - /* unsigned src1 * signed src2 */ - la_xvreplgr2vr_d(temp1, zero_ir2_opnd); - la_xvabsd_b(temp3, src2, temp1); - la_xvmaddwev_h_bu(temp1, src1, temp3); - la_xvreplgr2vr_d(temp2, zero_ir2_opnd); - la_xvmaddwod_h_bu(temp2, src1, temp3); - - la_ori(itmp, zero_ir2_opnd, 0x1); - la_xvreplgr2vr_b(temp3, itmp); - la_xvsigncov_b(temp4, src2, temp3); - - la_xvmulwev_h_b(temp5, temp4, temp3); - la_xvmulwod_h_b(temp3, temp4, temp3); - - la_xvmul_h(temp1, temp1, temp5); - la_xvmul_h(temp2, temp2, temp3); - la_xvsadd_h(dest, temp2, temp1); + IR2_OPND even = ra_alloc_ftemp(); + IR2_OPND odd = ra_alloc_ftemp(); + + la_xvmulwev_h_bu_b(even, src1, src2); + la_xvmulwod_h_bu_b(odd, src1, src2); + la_xvsadd_h(dest, even, odd); } return true; } From 0058d0288d40400a014b8bd6d756fa88f7ae5b66 Mon Sep 17 00:00:00 2001 From: Lu Zeng Date: Wed, 2 Sep 2026 18:36:17 +0800 Subject: [PATCH 6/6] LATX, AVX: write shuffle and byte-shift results directly Signed-off-by: Lu Zeng --- target/i386/latx/translator/tr-avx-shift.c | 4 +-- target/i386/latx/translator/tr-avx.c | 36 +++++++++++++--------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/target/i386/latx/translator/tr-avx-shift.c b/target/i386/latx/translator/tr-avx-shift.c index 6e75e3ece6..e89939163f 100644 --- a/target/i386/latx/translator/tr-avx-shift.c +++ b/target/i386/latx/translator/tr-avx-shift.c @@ -21,7 +21,7 @@ bool translate_vpslldq(IR1_INST * pir1) { lsassert((ir1_opnd_is_xmm(opnd0) && ir1_opnd_is_xmm(opnd1)) || (ir1_opnd_is_ymm(opnd0) && ir1_opnd_is_ymm(opnd1))); lsassert(ir1_opnd_is_imm(opnd2)); - IR2_OPND dest = load_freg256_from_ir1(opnd0); + IR2_OPND dest = ra_alloc_xmm(ir1_opnd_base_reg_num(opnd0)); IR2_OPND src = load_freg256_from_ir1(opnd1); uint8_t imm = ir1_opnd_uimm(opnd2); if (imm > 15) { @@ -118,7 +118,7 @@ bool translate_vpsrldq(IR1_INST * pir1) { lsassert((ir1_opnd_is_xmm(opnd0) && ir1_opnd_is_xmm(opnd1)) || (ir1_opnd_is_ymm(opnd0) && ir1_opnd_is_ymm(opnd1))); lsassert(ir1_opnd_is_imm(opnd2)); - IR2_OPND dest = load_freg256_from_ir1(opnd0); + IR2_OPND dest = ra_alloc_xmm(ir1_opnd_base_reg_num(opnd0)); IR2_OPND src = load_freg256_from_ir1(opnd1); uint8_t imm = ir1_opnd_uimm(opnd2); if (imm > 15) { diff --git a/target/i386/latx/translator/tr-avx.c b/target/i386/latx/translator/tr-avx.c index 16b6fe0546..f54099c70e 100644 --- a/target/i386/latx/translator/tr-avx.c +++ b/target/i386/latx/translator/tr-avx.c @@ -4094,15 +4094,13 @@ bool translate_vpshufd(IR1_INST * pir1) { IR2_OPND dest = load_freg128_from_ir1(opnd0); IR2_OPND src1 = load_freg128_from_ir1(opnd1); uint8_t imm = ir1_opnd_uimm(opnd2); - la_xvori_b(dest, src1, 0x00); - la_vpermi_w(dest, src1, imm); + la_xvshuf4i_w(dest, src1, imm); set_high128_xreg_to_zero(dest); } else { IR2_OPND dest = load_freg256_from_ir1(opnd0); IR2_OPND src1 = load_freg256_from_ir1(opnd1); uint8_t imm = ir1_opnd_uimm(opnd2); - la_xvori_b(dest, src1, 0x00); - la_xvpermi_w(dest, src1, imm); + la_xvshuf4i_w(dest, src1, imm); } return true; } @@ -4821,13 +4819,18 @@ bool translate_vpshufhw(IR1_INST *pir1) IR1_OPND *opnd1 = ir1_get_opnd(pir1, 1); IR1_OPND *opnd2 = ir1_get_opnd(pir1, 2); + uint64_t imm8 = ir1_opnd_uimm(opnd2); IR2_OPND dest = load_freg256_from_ir1(opnd0); IR2_OPND src = load_freg256_from_ir1(opnd1); - IR2_OPND temp = ra_alloc_ftemp(); - uint64_t imm8 = ir1_opnd_uimm(opnd2); - la_xvshuf4i_h(temp, src, imm8); - la_xvshuf4i_d(temp, src, 0x66); - la_xvori_b(dest, temp, 0); + if (dest._reg_num != src._reg_num) { + la_xvshuf4i_h(dest, src, imm8); + la_xvshuf4i_d(dest, src, 0x66); + } else { + IR2_OPND temp = ra_alloc_ftemp(); + la_xvshuf4i_h(temp, src, imm8); + la_xvshuf4i_d(temp, src, 0x66); + la_xvori_b(dest, temp, 0); + } if(ir1_opnd_is_xmm(opnd0)){ set_high128_xreg_to_zero(dest); } @@ -4846,13 +4849,18 @@ bool translate_vpshuflw(IR1_INST *pir1) IR1_OPND *opnd1 = ir1_get_opnd(pir1, 1); IR1_OPND *opnd2 = ir1_get_opnd(pir1, 2); + uint64_t imm8 = ir1_opnd_uimm(opnd2); IR2_OPND dest = load_freg256_from_ir1(opnd0); IR2_OPND src = load_freg256_from_ir1(opnd1); - IR2_OPND temp = ra_alloc_ftemp(); - uint64_t imm8 = ir1_opnd_uimm(opnd2); - la_xvshuf4i_h(temp, src, imm8); - la_xvshuf4i_d(temp, src, 0xcc); - la_xvori_b(dest, temp, 0); + if (dest._reg_num != src._reg_num) { + la_xvshuf4i_h(dest, src, imm8); + la_xvshuf4i_d(dest, src, 0xcc); + } else { + IR2_OPND temp = ra_alloc_ftemp(); + la_xvshuf4i_h(temp, src, imm8); + la_xvshuf4i_d(temp, src, 0xcc); + la_xvori_b(dest, temp, 0); + } if(ir1_opnd_is_xmm(opnd0)){ set_high128_xreg_to_zero(dest); }