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