Skip to content

Commit dece35c

Browse files
committed
LATX: inline glibc pcmpistri string modes
Signed-off-by: Lu Zeng <luzeng87@gmail.com>
1 parent 9bd2f78 commit dece35c

1 file changed

Lines changed: 175 additions & 2 deletions

File tree

target/i386/latx/translator/tr-simd.c

Lines changed: 175 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3646,6 +3646,169 @@ bool translate_pcmpestrm(IR1_INST *pir1)
36463646
return true;
36473647
}
36483648

3649+
static void tr_gen_inline_pcmpistri_prefix_mask(IR2_OPND prefix,
3650+
IR2_OPND vec,
3651+
IR2_OPND vtmp,
3652+
IR2_OPND tmp)
3653+
{
3654+
la_vor_v(vtmp, vec, vec);
3655+
la_vmsknz_b(vtmp, vtmp);
3656+
la_vpickve2gr_wu(prefix, vtmp, 0);
3657+
la_bstrpick_d(prefix, prefix, 15, 0);
3658+
3659+
/*
3660+
* Prefix mask before the first NUL:
3661+
* 0b...10111 -> ((mask ^ (mask + 1)) >> 1) == 0b00111
3662+
* 0xffff -> 0xffff
3663+
*/
3664+
la_addi_d(tmp, prefix, 1);
3665+
la_xor(prefix, prefix, tmp);
3666+
la_srli_d(prefix, prefix, 1);
3667+
la_bstrpick_d(prefix, prefix, 15, 0);
3668+
}
3669+
3670+
static void tr_gen_inline_pcmpistri_finish(IR2_OPND res,
3671+
IR2_OPND prefix_d,
3672+
IR2_OPND prefix_s)
3673+
{
3674+
IR2_OPND tmp = ra_alloc_itemp();
3675+
IR2_OPND flags = ra_alloc_itemp();
3676+
3677+
/*
3678+
* CF = res != 0, OF = res[0], ZF/SF indicate whether src/dst contain
3679+
* a NUL in the first 16 bytes. AF/PF are cleared.
3680+
*/
3681+
la_mov64(flags, zero_ir2_opnd);
3682+
la_sltu(tmp, zero_ir2_opnd, res);
3683+
la_or(flags, flags, tmp);
3684+
3685+
la_andi(tmp, res, 1);
3686+
la_bstrins_w(flags, tmp, OF_BIT_INDEX, OF_BIT_INDEX);
3687+
3688+
li_d(tmp, 0xffff);
3689+
la_xor(tmp, prefix_s, tmp);
3690+
la_sltu(tmp, zero_ir2_opnd, tmp);
3691+
la_bstrins_w(flags, tmp, ZF_BIT_INDEX, ZF_BIT_INDEX);
3692+
3693+
li_d(tmp, 0xffff);
3694+
la_xor(tmp, prefix_d, tmp);
3695+
la_sltu(tmp, zero_ir2_opnd, tmp);
3696+
la_bstrins_w(flags, tmp, SF_BIT_INDEX, SF_BIT_INDEX);
3697+
3698+
la_x86mtflag(flags, CF_USEDEF_BIT | PF_USEDEF_BIT | AF_USEDEF_BIT |
3699+
ZF_USEDEF_BIT | SF_USEDEF_BIT | OF_USEDEF_BIT);
3700+
3701+
/* ECX = res ? ctz(res) : 16 */
3702+
la_ctz_w(tmp, res);
3703+
la_addi_d(flags, zero_ir2_opnd, 16);
3704+
la_maskeqz(tmp, tmp, res);
3705+
la_masknez(flags, flags, res);
3706+
la_or(tmp, tmp, flags);
3707+
la_mov64(ra_alloc_gpr(ecx_index), tmp);
3708+
3709+
ra_free_temp(flags);
3710+
ra_free_temp(tmp);
3711+
}
3712+
3713+
static void tr_gen_inline_pcmpistri_equal_each_negative(IR2_OPND vd,
3714+
IR2_OPND vs)
3715+
{
3716+
IR2_OPND vd_nz = ra_alloc_ftemp();
3717+
IR2_OPND vs_nz = ra_alloc_ftemp();
3718+
IR2_OPND vcmp = ra_alloc_ftemp();
3719+
3720+
IR2_OPND eq_mask = ra_alloc_itemp();
3721+
IR2_OPND prefix_d = ra_alloc_itemp();
3722+
IR2_OPND prefix_s = ra_alloc_itemp();
3723+
IR2_OPND res = ra_alloc_itemp();
3724+
IR2_OPND tmp = ra_alloc_itemp();
3725+
3726+
la_vseq_b(vcmp, vd, vs);
3727+
la_vmsknz_b(vcmp, vcmp);
3728+
la_vpickve2gr_wu(eq_mask, vcmp, 0);
3729+
la_bstrpick_d(eq_mask, eq_mask, 15, 0);
3730+
3731+
tr_gen_inline_pcmpistri_prefix_mask(prefix_d, vd, vd_nz, tmp);
3732+
tr_gen_inline_pcmpistri_prefix_mask(prefix_s, vs, vs_nz, tmp);
3733+
3734+
ra_free_temp(vcmp);
3735+
ra_free_temp(vs_nz);
3736+
ra_free_temp(vd_nz);
3737+
ra_free_temp(tmp);
3738+
3739+
la_or(res, prefix_d, prefix_s);
3740+
la_nor(eq_mask, eq_mask, zero_ir2_opnd);
3741+
la_bstrpick_d(eq_mask, eq_mask, 15, 0);
3742+
la_and(res, res, eq_mask);
3743+
3744+
tr_gen_inline_pcmpistri_finish(res, prefix_d, prefix_s);
3745+
3746+
ra_free_temp(res);
3747+
ra_free_temp(prefix_s);
3748+
ra_free_temp(prefix_d);
3749+
ra_free_temp(eq_mask);
3750+
}
3751+
3752+
static void tr_gen_inline_pcmpistri_self_nul_probe(IR2_OPND vd)
3753+
{
3754+
IR2_OPND vtmp = ra_alloc_ftemp();
3755+
IR2_OPND prefix = ra_alloc_itemp();
3756+
IR2_OPND res = ra_alloc_itemp();
3757+
IR2_OPND tmp = ra_alloc_itemp();
3758+
3759+
tr_gen_inline_pcmpistri_prefix_mask(prefix, vd, vtmp, tmp);
3760+
ra_free_temp(vtmp);
3761+
ra_free_temp(tmp);
3762+
3763+
la_nor(res, prefix, zero_ir2_opnd);
3764+
la_bstrpick_d(res, res, 15, 0);
3765+
3766+
tr_gen_inline_pcmpistri_finish(res, prefix, prefix);
3767+
3768+
ra_free_temp(res);
3769+
ra_free_temp(prefix);
3770+
}
3771+
3772+
/*
3773+
* glibc string fast paths use:
3774+
* pcmpistri xmm, xmm/m128, 0x18/0x1a
3775+
* Equal Each, negative polarity, least-significant index.
3776+
* 0x18 vs 0x1a differs only in unsigned/signed byte elements, which does
3777+
* not change byte equality.
3778+
* pcmpistri xmm, xmm, 0x3a
3779+
* Equal Each, masked negative polarity, least-significant index. glibc
3780+
* uses only the self-compare form as a NUL-position probe.
3781+
*
3782+
* Other modes have different aggregation/polarity/index semantics and stay on
3783+
* the helper path.
3784+
*/
3785+
static bool tr_gen_inline_pcmpistri(IR1_INST *pir1, IR2_OPND vd, IR2_OPND vs,
3786+
int ctrl)
3787+
{
3788+
if (ctrl == 0x18 || ctrl == 0x1a) {
3789+
tr_gen_inline_pcmpistri_equal_each_negative(vd, vs);
3790+
return true;
3791+
}
3792+
3793+
if (ctrl == 0x3a) {
3794+
IR1_OPND *opnd0 = ir1_get_opnd(pir1, 0);
3795+
IR1_OPND *opnd1 = ir1_get_opnd(pir1, 1);
3796+
3797+
if (ir1_opnd_is_xmm(opnd1) &&
3798+
ir1_opnd_base_reg_num(opnd0) == ir1_opnd_base_reg_num(opnd1)) {
3799+
tr_gen_inline_pcmpistri_self_nul_probe(vd);
3800+
return true;
3801+
}
3802+
}
3803+
3804+
return false;
3805+
}
3806+
3807+
static bool tr_pcmpistri_mem_can_inline(int ctrl)
3808+
{
3809+
return ctrl == 0x18 || ctrl == 0x1a;
3810+
}
3811+
36493812
#ifndef CONFIG_LATX_AVX_OPT
36503813
bool translate_pcmpistri(IR1_INST *pir1)
36513814
#else
@@ -3659,8 +3822,18 @@ bool translate_vpcmpistri(IR1_INST *pir1)
36593822
int d = ir1_opnd_base_reg_num(opnd0);
36603823
if (ir1_opnd_is_xmm(opnd1)) {
36613824
int s = ir1_opnd_base_reg_num(opnd1);
3662-
tr_gen_call_to_helper_pcmpxstrx((ADDR)helper_pcmpistri_xmm, d, s, imm,
3663-
LOAD_HELPER_PCMPISTRI_XMM);
3825+
IR2_OPND vd = ra_alloc_xmm(d);
3826+
IR2_OPND vs = ra_alloc_xmm(s);
3827+
if (!tr_gen_inline_pcmpistri(pir1, vd, vs, imm)) {
3828+
tr_gen_call_to_helper_pcmpxstrx((ADDR)helper_pcmpistri_xmm, d, s, imm,
3829+
LOAD_HELPER_PCMPISTRI_XMM);
3830+
}
3831+
} else if (tr_pcmpistri_mem_can_inline(imm)) {
3832+
IR2_OPND vd = ra_alloc_xmm(d);
3833+
IR2_OPND vs = ra_alloc_ftemp();
3834+
load_freg128_from_ir1_mem(vs, opnd1);
3835+
tr_gen_inline_pcmpistri(pir1, vd, vs, imm);
3836+
ra_free_temp(vs);
36643837
} else {
36653838
IR2_OPND temp = ra_alloc_ftemp();
36663839
IR2_OPND src = ra_alloc_xmm((d + 1) % 8);

0 commit comments

Comments
 (0)