Message ID | 20230328030631.3117129-39-gaosong@loongson.cn |
---|---|
State | New |
Headers | show |
Series | Add LoongArch LSX instructions | expand |
On 3/27/23 20:06, Song Gao wrote: > +static void gen_vbitseli(unsigned vece, TCGv_vec a, TCGv_vec b, int64_t imm) > +{ > + TCGv_vec t; > + > + t = tcg_temp_new_vec_matching(a); > + tcg_gen_dupi_vec(vece, t, imm); tcg_constant_vec_matching. > +void HELPER(vseteqz_v)(CPULoongArchState *env, uint32_t cd, uint32_t vj) > +{ > + VReg *Vj = &(env->fpr[vj].vreg); > + env->cf[cd & 0x7] = (Vj->Q(0) == 0); > +} > + > +void HELPER(vsetnez_v)(CPULoongArchState *env, uint32_t cd, uint32_t vj) > +{ > + VReg *Vj = &(env->fpr[vj].vreg); > + env->cf[cd & 0x7] = (Vj->Q(0) != 0); > +} This is trivial inline. > +#define SETANYEQZ(NAME, BIT, E) \ > +void HELPER(NAME)(CPULoongArchState *env, uint32_t cd, uint32_t vj) \ > +{ \ > + int i; \ > + bool ret = false; \ > + VReg *Vj = &(env->fpr[vj].vreg); \ > + \ > + for (i = 0; i < LSX_LEN/BIT; i++) { \ > + ret |= (Vj->E(i) == 0); \ > + } \ > + env->cf[cd & 0x7] = ret; \ > +} > +SETANYEQZ(vsetanyeqz_b, 8, B) > +SETANYEQZ(vsetanyeqz_h, 16, H) > +SETANYEQZ(vsetanyeqz_w, 32, W) > +SETANYEQZ(vsetanyeqz_d, 64, D) These could be inlined, though slightly harder. C.f. target/arm/sve_helper.c, do_match2 (your n == 0). Anyway, leaving this as-is for now is also ok. r~
在 2023/4/4 上午9:03, Richard Henderson 写道: >> +void HELPER(vseteqz_v)(CPULoongArchState *env, uint32_t cd, uint32_t >> vj) >> +{ >> + VReg *Vj = &(env->fpr[vj].vreg); >> + env->cf[cd & 0x7] = (Vj->Q(0) == 0); >> +} >> + >> +void HELPER(vsetnez_v)(CPULoongArchState *env, uint32_t cd, uint32_t >> vj) >> +{ >> + VReg *Vj = &(env->fpr[vj].vreg); >> + env->cf[cd & 0x7] = (Vj->Q(0) != 0); >> +} > > This is trivial inline. e.g static bool trans_vseteqz_v(DisasContext *ctx, arg_cv *a) { TCGv_i64 t1, t2, al, ah, zero; al = tcg_temp_new_i64(); ah = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); t2 = tcg_temp_new_i64(); zero = tcg_constant_i64(0); get_vreg64(ah, a->vj, 1); get_vreg64(al, a->vj, 0); CHECK_SXE; tcg_gen_setcond_i64(TCG_COND_EQ, t1, al, zero); tcg_gen_setcond_i64(TCG_COND_EQ, t2, ah, zero); tcg_gen_and_i64(t1, t1, t2); tcg_gen_st8_tl(t1, cpu_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); return true; } and static bool trans_vsetnez_v(DisasContext *ctx, arg_cv *a) { TCGv_i64 t1, t2, al, ah, zero; al = tcg_temp_new_i64(); ah = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); t2 = tcg_temp_new_i64(); zero = tcg_constant_i64(0); get_vreg64(ah, a->vj, 1); get_vreg64(al, a->vj, 0); CHECK_SXE; tcg_gen_setcond_i64(TCG_COND_NE, t1, al, zero); tcg_gen_setcond_i64(TCG_COND_NE, t2, ah, zero); tcg_gen_or_i64(t1, t1, t2); tcg_gen_st8_tl(t1, cpu_env, offsetof(CPULoongArchState, cf[a->cd & 0x7])); return true; } >> +#define SETANYEQZ(NAME, BIT, E) \ >> +void HELPER(NAME)(CPULoongArchState *env, uint32_t cd, uint32_t vj) \ >> +{ \ >> + int i; \ >> + bool ret = false; \ >> + VReg *Vj = &(env->fpr[vj].vreg); \ >> + \ >> + for (i = 0; i < LSX_LEN/BIT; i++) { \ >> + ret |= (Vj->E(i) == 0); \ >> + } \ >> + env->cf[cd & 0x7] = ret; \ >> +} >> +SETANYEQZ(vsetanyeqz_b, 8, B) >> +SETANYEQZ(vsetanyeqz_h, 16, H) >> +SETANYEQZ(vsetanyeqz_w, 32, W) >> +SETANYEQZ(vsetanyeqz_d, 64, D) > > These could be inlined, though slightly harder. > C.f. target/arm/sve_helper.c, do_match2 (your n == 0). > Do you mean an inline like trans_vseteqz_v or just an inline helper function? Thanks. Song Gao > Anyway, leaving this as-is for now is also ok.
On 4/11/23 13:37, gaosong wrote: > static bool trans_vseteqz_v(DisasContext *ctx, arg_cv *a) > { > TCGv_i64 t1, t2, al, ah, zero; > > al = tcg_temp_new_i64(); > ah = tcg_temp_new_i64(); > t1 = tcg_temp_new_i64(); > t2 = tcg_temp_new_i64(); > zero = tcg_constant_i64(0); > > get_vreg64(ah, a->vj, 1); > get_vreg64(al, a->vj, 0); > > CHECK_SXE; > tcg_gen_setcond_i64(TCG_COND_EQ, t1, al, zero); > tcg_gen_setcond_i64(TCG_COND_EQ, t2, ah, zero); > tcg_gen_and_i64(t1, t1, t2); tcg_gen_or_i64(t1, al, ah); tcg_gen_setcondi_i64(TCG_COND_EQ, t1, t1, 0 But otherwise correct, yes. >>> +#define SETANYEQZ(NAME, BIT, E) \ >>> +void HELPER(NAME)(CPULoongArchState *env, uint32_t cd, uint32_t vj) \ >>> +{ \ >>> + int i; \ >>> + bool ret = false; \ >>> + VReg *Vj = &(env->fpr[vj].vreg); \ >>> + \ >>> + for (i = 0; i < LSX_LEN/BIT; i++) { \ >>> + ret |= (Vj->E(i) == 0); \ >>> + } \ >>> + env->cf[cd & 0x7] = ret; \ >>> +} >>> +SETANYEQZ(vsetanyeqz_b, 8, B) >>> +SETANYEQZ(vsetanyeqz_h, 16, H) >>> +SETANYEQZ(vsetanyeqz_w, 32, W) >>> +SETANYEQZ(vsetanyeqz_d, 64, D) >> >> These could be inlined, though slightly harder. >> C.f. target/arm/sve_helper.c, do_match2 (your n == 0). >> > Do you mean an inline like trans_vseteqz_v or just an inline helper function? I meant inline tcg code generation, instead of a call to a helper. But even if we keep this in a helper, see do_match2 for avoiding the loop over bytes. r~
在 2023/4/12 下午2:53, Richard Henderson 写道: > >>>> +#define SETANYEQZ(NAME, BIT, E) \ >>>> +void HELPER(NAME)(CPULoongArchState *env, uint32_t cd, uint32_t vj) \ >>>> +{ \ >>>> + int i; \ >>>> + bool ret = false; \ >>>> + VReg *Vj = &(env->fpr[vj].vreg); \ >>>> + \ >>>> + for (i = 0; i < LSX_LEN/BIT; i++) { \ >>>> + ret |= (Vj->E(i) == 0); \ >>>> + } \ >>>> + env->cf[cd & 0x7] = ret; \ >>>> +} >>>> +SETANYEQZ(vsetanyeqz_b, 8, B) >>>> +SETANYEQZ(vsetanyeqz_h, 16, H) >>>> +SETANYEQZ(vsetanyeqz_w, 32, W) >>>> +SETANYEQZ(vsetanyeqz_d, 64, D) >>> >>> These could be inlined, though slightly harder. >>> C.f. target/arm/sve_helper.c, do_match2 (your n == 0). >>> >> Do you mean an inline like trans_vseteqz_v or just an inline helper >> function? > > I meant inline tcg code generation, instead of a call to a helper. > But even if we keep this in a helper, see do_match2 for avoiding the > loop over bytes. Ok, e.g #define SETANYEQZ(NAME, MO) \ void HELPER(NAME)(CPULoongArchState *env, uint32_t cd, uint32_t vj) \ { \ int i; \ bool ret = false; \ VReg *Vj = &(env->fpr[vj].vreg); \ \ ret = do_match2(0, (uint64_t)Vj->D(0), (uint64_t)Vj->D(1), MO); \ env->cf[cd & 0x7] = ret; \ } SETANYEQZ(vsetanyeqz_b, MO_8) SETANYEQZ(vsetanyeqz_h, MO_16) SETANYEQZ(vsetanyeqz_w, MO_32) SETANYEQZ(vsetanyeqz_d, MO_64) and vsetanyeqz.b $fcc5 $vr11 v11 : {edc0004d576eef5b, ec03ec0fec03ea47} ------------------ do_match2 bits is 8 m1 is ec03ec0fec03ea47 m0 is edc0004d576eef5b ones is 1010101 sings is 80808080 cmp1 is 0 cmp0 is edc0004d576eef5b cmp1 is ec03ec0fec03ea47 cmp0 is 10000 cmp1 is 3000100 ret is 0 but, the results is not correct for vsetanyeqz.b. :-) Thanks. Song Gao
On 4/13/23 04:53, gaosong wrote: > > 在 2023/4/12 下午2:53, Richard Henderson 写道: >> >>>>> +#define SETANYEQZ(NAME, BIT, E) \ >>>>> +void HELPER(NAME)(CPULoongArchState *env, uint32_t cd, uint32_t vj) \ >>>>> +{ \ >>>>> + int i; \ >>>>> + bool ret = false; \ >>>>> + VReg *Vj = &(env->fpr[vj].vreg); \ >>>>> + \ >>>>> + for (i = 0; i < LSX_LEN/BIT; i++) { \ >>>>> + ret |= (Vj->E(i) == 0); \ >>>>> + } \ >>>>> + env->cf[cd & 0x7] = ret; \ >>>>> +} >>>>> +SETANYEQZ(vsetanyeqz_b, 8, B) >>>>> +SETANYEQZ(vsetanyeqz_h, 16, H) >>>>> +SETANYEQZ(vsetanyeqz_w, 32, W) >>>>> +SETANYEQZ(vsetanyeqz_d, 64, D) >>>> >>>> These could be inlined, though slightly harder. >>>> C.f. target/arm/sve_helper.c, do_match2 (your n == 0). >>>> >>> Do you mean an inline like trans_vseteqz_v or just an inline helper function? >> >> I meant inline tcg code generation, instead of a call to a helper. >> But even if we keep this in a helper, see do_match2 for avoiding the loop over bytes. > Ok, > e.g > #define SETANYEQZ(NAME, MO) \ > void HELPER(NAME)(CPULoongArchState *env, uint32_t cd, uint32_t vj) \ > { \ > int i; \ > bool ret = false; \ > VReg *Vj = &(env->fpr[vj].vreg); \ > \ > ret = do_match2(0, (uint64_t)Vj->D(0), (uint64_t)Vj->D(1), MO); \ > env->cf[cd & 0x7] = ret; \ > } > SETANYEQZ(vsetanyeqz_b, MO_8) > SETANYEQZ(vsetanyeqz_h, MO_16) > SETANYEQZ(vsetanyeqz_w, MO_32) > SETANYEQZ(vsetanyeqz_d, MO_64) > > and > vsetanyeqz.b $fcc5 $vr11 > v11 : {edc0004d576eef5b, ec03ec0fec03ea47} > ------------------ > do_match2 > bits is 8 > m1 is ec03ec0fec03ea47 > m0 is edc0004d576eef5b > ones is 1010101 > sings is 80808080 > cmp1 is 0 > cmp0 is edc0004d576eef5b > cmp1 is ec03ec0fec03ea47 > cmp0 is 10000 > cmp1 is 3000100 > ret is 0 > > but, the results is not correct for vsetanyeqz.b. :-) Well, 'ones' as printed above is only 4 bytes instead of 8, similarly 'sings'. That would certainly explain why it did not detect a zero in byte 5 of 'm0'. Some problem with your conversion of that function? r~
在 2023/4/13 下午6:06, Richard Henderson 写道: > On 4/13/23 04:53, gaosong wrote: >> >> 在 2023/4/12 下午2:53, Richard Henderson 写道: >>> >>>>>> +#define SETANYEQZ(NAME, BIT, E) \ >>>>>> +void HELPER(NAME)(CPULoongArchState *env, uint32_t cd, uint32_t >>>>>> vj) \ >>>>>> +{ >>>>>> \ >>>>>> + int i; \ >>>>>> + bool ret = >>>>>> false; \ >>>>>> + VReg *Vj = &(env->fpr[vj].vreg); \ >>>>>> + >>>>>> \ >>>>>> + for (i = 0; i < LSX_LEN/BIT; i++) >>>>>> { \ >>>>>> + ret |= (Vj->E(i) == >>>>>> 0); \ >>>>>> + } \ >>>>>> + env->cf[cd & 0x7] = >>>>>> ret; \ >>>>>> +} >>>>>> +SETANYEQZ(vsetanyeqz_b, 8, B) >>>>>> +SETANYEQZ(vsetanyeqz_h, 16, H) >>>>>> +SETANYEQZ(vsetanyeqz_w, 32, W) >>>>>> +SETANYEQZ(vsetanyeqz_d, 64, D) >>>>> >>>>> These could be inlined, though slightly harder. >>>>> C.f. target/arm/sve_helper.c, do_match2 (your n == 0). >>>>> >>>> Do you mean an inline like trans_vseteqz_v or just an inline helper >>>> function? >>> >>> I meant inline tcg code generation, instead of a call to a helper. >>> But even if we keep this in a helper, see do_match2 for avoiding the >>> loop over bytes. >> Ok, >> e.g >> #define SETANYEQZ(NAME, MO) \ >> void HELPER(NAME)(CPULoongArchState *env, uint32_t cd, uint32_t vj) \ >> { \ >> int i; \ >> bool ret = false; \ >> VReg *Vj = &(env->fpr[vj].vreg); \ >> \ >> ret = do_match2(0, (uint64_t)Vj->D(0), (uint64_t)Vj->D(1), >> MO); \ >> env->cf[cd & 0x7] = ret; \ >> } >> SETANYEQZ(vsetanyeqz_b, MO_8) >> SETANYEQZ(vsetanyeqz_h, MO_16) >> SETANYEQZ(vsetanyeqz_w, MO_32) >> SETANYEQZ(vsetanyeqz_d, MO_64) >> >> and >> vsetanyeqz.b $fcc5 $vr11 >> v11 : {edc0004d576eef5b, ec03ec0fec03ea47} >> ------------------ >> do_match2 >> bits is 8 >> m1 is ec03ec0fec03ea47 >> m0 is edc0004d576eef5b >> ones is 1010101 >> sings is 80808080 >> cmp1 is 0 >> cmp0 is edc0004d576eef5b >> cmp1 is ec03ec0fec03ea47 >> cmp0 is 10000 >> cmp1 is 3000100 >> ret is 0 >> >> but, the results is not correct for vsetanyeqz.b. :-) > > Well, 'ones' as printed above is only 4 bytes instead of 8, similarly > 'sings'. That would certainly explain why it did not detect a zero in > byte 5 of 'm0'. > > Some problem with your conversion of that function? > I copied do_match2 from arm. and my host is x86 machine. ... uint64_t ones = dup_const(esz, 1); // esz = MO_8 uint64_t signs = ones << ( bits -1 ); // bits = 8 ... the dup_const() return 0x101010101010101. but set the 'ones' is 0x1010101. Thread 1 "qemu-loongarch6" hit Breakpoint 1, helper_vsetanyeqz_b (env=0x555555a50910, cd=6, vj=3) at ../target/loongarch/lsx_helper.c:2906 2906 SETANYEQZ(vsetanyeqz_b, MO_8, B) (gdb) s do_match2 (n=0, m0=14467753019624114359, m1=14467753019624114359, esz=0) at ../target/loongarch/lsx_helper.c:2868 2868 uint64_t bits = 8 << esz; (gdb) s 2869 uint64_t ones = dup_const(esz, 1); (gdb) s dup_const (vece=0, c=1) at ../tcg/tcg-op-gvec.c:374 374 switch (vece) { (gdb) finish Run till exit from #0 dup_const (vece=0, c=1) at ../tcg/tcg-op-gvec.c:374 do_match2 (n=0, m0=14467753019624114359, m1=14467753019624114359, esz=0) at ../target/loongarch/lsx_helper.c:2869 2869 uint64_t ones = dup_const(esz, 1); Value returned is $16 = 72340172838076673 (gdb) disassemble $pc Dump of assembler code for function do_match2: 0x00005555555fffdf <+0>: push %rbp 0x00005555555fffe0 <+1>: mov %rsp,%rbp 0x00005555555fffe3 <+4>: sub $0x50,%rsp 0x00005555555fffe7 <+8>: mov %rdi,-0x38(%rbp) 0x00005555555fffeb <+12>: mov %rsi,-0x40(%rbp) 0x00005555555fffef <+16>: mov %rdx,-0x48(%rbp) 0x00005555555ffff3 <+20>: mov %ecx,-0x4c(%rbp) 0x00005555555ffff6 <+23>: mov -0x4c(%rbp),%eax 0x00005555555ffff9 <+26>: mov $0x8,%edx 0x00005555555ffffe <+31>: mov %eax,%ecx 0x0000555555600000 <+33>: shl %cl,%edx 0x0000555555600002 <+35>: mov %edx,%eax 0x0000555555600004 <+37>: cltq 0x0000555555600006 <+39>: mov %rax,-0x28(%rbp) 0x000055555560000a <+43>: mov -0x4c(%rbp),%eax 0x000055555560000d <+46>: mov $0x1,%esi 0x0000555555600012 <+51>: mov %eax,%edi 0x0000555555600014 <+53>: mov $0x0,%eax 0x0000555555600019 <+58>: callq 0x5555556342c3 <dup_const> => 0x000055555560001e <+63>: cltq 0x0000555555600020 <+65>: mov %rax,-0x20(%rbp) 0x0000555555600024 <+69>: mov -0x28(%rbp),%rax 0x0000555555600028 <+73>: sub $0x1,%eax 0x000055555560002b <+76>: mov -0x20(%rbp),%rdx 0x000055555560002f <+80>: mov %eax,%ecx 0x0000555555600031 <+82>: shl %cl,%rdx 0x0000555555600034 <+85>: mov %rdx,%rax 0x0000555555600037 <+88>: mov %rax,-0x18(%rbp) 0x000055555560003b <+92>: lea 0x129df7(%rip),%rdi # 0x555555729e39 0x0000555555600042 <+99>: callq 0x555555583af0 <puts@plt> 0x0000555555600047 <+104>: mov -0x4c(%rbp),%eax --Type <RET> for more, q to quit, c to continue without paging--q Quit (gdb) p/x $rax $17 = 0x101010101010101 (gdb) si 0x0000555555600020 2869 uint64_t ones = dup_const(esz, 1); (gdb) p/x $rax $18 = 0x1010101 (gdb) disassemble $pc Dump of assembler code for function do_match2: 0x00005555555fffdf <+0>: push %rbp 0x00005555555fffe0 <+1>: mov %rsp,%rbp 0x00005555555fffe3 <+4>: sub $0x50,%rsp 0x00005555555fffe7 <+8>: mov %rdi,-0x38(%rbp) 0x00005555555fffeb <+12>: mov %rsi,-0x40(%rbp) 0x00005555555fffef <+16>: mov %rdx,-0x48(%rbp) 0x00005555555ffff3 <+20>: mov %ecx,-0x4c(%rbp) 0x00005555555ffff6 <+23>: mov -0x4c(%rbp),%eax 0x00005555555ffff9 <+26>: mov $0x8,%edx 0x00005555555ffffe <+31>: mov %eax,%ecx 0x0000555555600000 <+33>: shl %cl,%edx 0x0000555555600002 <+35>: mov %edx,%eax 0x0000555555600004 <+37>: cltq 0x0000555555600006 <+39>: mov %rax,-0x28(%rbp) 0x000055555560000a <+43>: mov -0x4c(%rbp),%eax 0x000055555560000d <+46>: mov $0x1,%esi 0x0000555555600012 <+51>: mov %eax,%edi 0x0000555555600014 <+53>: mov $0x0,%eax 0x0000555555600019 <+58>: callq 0x5555556342c3 <dup_const> 0x000055555560001e <+63>: cltq => 0x0000555555600020 <+65>: mov %rax,-0x20(%rbp) 0x0000555555600024 <+69>: mov -0x28(%rbp),%rax 0x0000555555600028 <+73>: sub $0x1,%eax 0x000055555560002b <+76>: mov -0x20(%rbp),%rdx 0x000055555560002f <+80>: mov %eax,%ecx 0x0000555555600031 <+82>: shl %cl,%rdx 0x0000555555600034 <+85>: mov %rdx,%rax 0x0000555555600037 <+88>: mov %rax,-0x18(%rbp) 0x000055555560003b <+92>: lea 0x129df7(%rip),%rdi # 0x555555729e39 0x0000555555600042 <+99>: callq 0x555555583af0 <puts@plt> 0x0000555555600047 <+104>: mov -0x4c(%rbp),%eax --Type <RET> for more, q to quit, c to continue without paging--q Quit (gdb) p/x ones $19 = 0x7fffffffc850 (gdb) si 2871 uint64_t signs = ones << (bits - 1); (gdb) p/x $rax $20 = 0x1010101 (gdb) p/x ones $21 = 0x1010101 After exec insn 'cltq' , the 'ones' is not we want. Thanks. Song Gao
在 2023/4/14 上午11:22, gaosong 写道: > > 在 2023/4/13 下午6:06, Richard Henderson 写道: >> On 4/13/23 04:53, gaosong wrote: >>> >>> 在 2023/4/12 下午2:53, Richard Henderson 写道: >>>> >>>>>>> +#define SETANYEQZ(NAME, BIT, E) \ >>>>>>> +void HELPER(NAME)(CPULoongArchState *env, uint32_t cd, uint32_t >>>>>>> vj) \ >>>>>>> +{ >>>>>>> \ >>>>>>> + int i; \ >>>>>>> + bool ret = >>>>>>> false; \ >>>>>>> + VReg *Vj = &(env->fpr[vj].vreg); \ >>>>>>> + >>>>>>> \ >>>>>>> + for (i = 0; i < LSX_LEN/BIT; i++) >>>>>>> { \ >>>>>>> + ret |= (Vj->E(i) == >>>>>>> 0); \ >>>>>>> + } \ >>>>>>> + env->cf[cd & 0x7] = >>>>>>> ret; \ >>>>>>> +} >>>>>>> +SETANYEQZ(vsetanyeqz_b, 8, B) >>>>>>> +SETANYEQZ(vsetanyeqz_h, 16, H) >>>>>>> +SETANYEQZ(vsetanyeqz_w, 32, W) >>>>>>> +SETANYEQZ(vsetanyeqz_d, 64, D) >>>>>> >>>>>> These could be inlined, though slightly harder. >>>>>> C.f. target/arm/sve_helper.c, do_match2 (your n == 0). >>>>>> >>>>> Do you mean an inline like trans_vseteqz_v or just an inline >>>>> helper function? >>>> >>>> I meant inline tcg code generation, instead of a call to a helper. >>>> But even if we keep this in a helper, see do_match2 for avoiding >>>> the loop over bytes. >>> Ok, >>> e.g >>> #define SETANYEQZ(NAME, MO) \ >>> void HELPER(NAME)(CPULoongArchState *env, uint32_t cd, uint32_t vj) \ >>> { \ >>> int i; \ >>> bool ret = false; \ >>> VReg *Vj = &(env->fpr[vj].vreg); \ >>> \ >>> ret = do_match2(0, (uint64_t)Vj->D(0), (uint64_t)Vj->D(1), >>> MO); \ >>> env->cf[cd & 0x7] = ret; \ >>> } >>> SETANYEQZ(vsetanyeqz_b, MO_8) >>> SETANYEQZ(vsetanyeqz_h, MO_16) >>> SETANYEQZ(vsetanyeqz_w, MO_32) >>> SETANYEQZ(vsetanyeqz_d, MO_64) >>> >>> and >>> vsetanyeqz.b $fcc5 $vr11 >>> v11 : {edc0004d576eef5b, ec03ec0fec03ea47} >>> ------------------ >>> do_match2 >>> bits is 8 >>> m1 is ec03ec0fec03ea47 >>> m0 is edc0004d576eef5b >>> ones is 1010101 >>> sings is 80808080 >>> cmp1 is 0 >>> cmp0 is edc0004d576eef5b >>> cmp1 is ec03ec0fec03ea47 >>> cmp0 is 10000 >>> cmp1 is 3000100 >>> ret is 0 >>> >>> but, the results is not correct for vsetanyeqz.b. :-) >> >> Well, 'ones' as printed above is only 4 bytes instead of 8, similarly >> 'sings'. That would certainly explain why it did not detect a zero >> in byte 5 of 'm0'. >> >> Some problem with your conversion of that function? >> > I copied do_match2 from arm. and my host is x86 machine. > > ... > uint64_t ones = dup_const(esz, 1); // esz = MO_8 > uint64_t signs = ones << ( bits -1 ); // bits = 8 > ... > > > the dup_const() return 0x101010101010101. > > but set the 'ones' is 0x1010101. > > Oh, I didn't include the 'tcg/tcg.h' header file. Thanks. Song gao
diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c index 64db01d2f9..ecf0c7b577 100644 --- a/target/loongarch/disas.c +++ b/target/loongarch/disas.c @@ -792,6 +792,12 @@ static bool trans_##insn(DisasContext *ctx, arg_##type * a) \ return true; \ } +static void output_cv(DisasContext *ctx, arg_cv *a, + const char *mnemonic) +{ + output(ctx, mnemonic, "fcc%d, v%d", a->cd, a->vj); +} + static void output_vvv(DisasContext *ctx, arg_vvv *a, const char *mnemonic) { output(ctx, mnemonic, "v%d, v%d, v%d", a->vd, a->vj, a->vk); @@ -1541,3 +1547,17 @@ static bool trans_vfcmp_cond_##suffix(DisasContext *ctx, \ LSX_FCMP_INSN(s) LSX_FCMP_INSN(d) + +INSN_LSX(vbitsel_v, vvvv) +INSN_LSX(vbitseli_b, vv_i) + +INSN_LSX(vseteqz_v, cv) +INSN_LSX(vsetnez_v, cv) +INSN_LSX(vsetanyeqz_b, cv) +INSN_LSX(vsetanyeqz_h, cv) +INSN_LSX(vsetanyeqz_w, cv) +INSN_LSX(vsetanyeqz_d, cv) +INSN_LSX(vsetallnez_b, cv) +INSN_LSX(vsetallnez_h, cv) +INSN_LSX(vsetallnez_w, cv) +INSN_LSX(vsetallnez_d, cv) diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index ef0b67349d..cdc007a072 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -655,3 +655,16 @@ DEF_HELPER_5(vfcmp_c_s, void, env, i32, i32, i32, i32) DEF_HELPER_5(vfcmp_s_s, void, env, i32, i32, i32, i32) DEF_HELPER_5(vfcmp_c_d, void, env, i32, i32, i32, i32) DEF_HELPER_5(vfcmp_s_d, void, env, i32, i32, i32, i32) + +DEF_HELPER_FLAGS_4(vbitseli_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_3(vseteqz_v, void, env, i32, i32) +DEF_HELPER_3(vsetnez_v, void, env, i32, i32) +DEF_HELPER_3(vsetanyeqz_b, void, env, i32, i32) +DEF_HELPER_3(vsetanyeqz_h, void, env, i32, i32) +DEF_HELPER_3(vsetanyeqz_w, void, env, i32, i32) +DEF_HELPER_3(vsetanyeqz_d, void, env, i32, i32) +DEF_HELPER_3(vsetallnez_b, void, env, i32, i32) +DEF_HELPER_3(vsetallnez_h, void, env, i32, i32) +DEF_HELPER_3(vsetallnez_w, void, env, i32, i32) +DEF_HELPER_3(vsetallnez_d, void, env, i32, i32) diff --git a/target/loongarch/insn_trans/trans_lsx.c.inc b/target/loongarch/insn_trans/trans_lsx.c.inc index 593b8b481d..7fc5c6c1d6 100644 --- a/target/loongarch/insn_trans/trans_lsx.c.inc +++ b/target/loongarch/insn_trans/trans_lsx.c.inc @@ -65,6 +65,17 @@ static bool gen_vv_i(DisasContext *ctx, arg_vv_i *a, return true; } +static bool gen_cv(DisasContext *ctx, arg_cv *a, + void (*func)(TCGv_ptr, TCGv_i32, TCGv_i32)) +{ + TCGv_i32 vj = tcg_constant_i32(a->vj); + TCGv_i32 cd = tcg_constant_i32(a->cd); + + CHECK_SXE; + func(cpu_env, cd, vj); + return true; +} + static bool gvec_vvv(DisasContext *ctx, arg_vvv *a, MemOp mop, void (*func)(unsigned, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t)) @@ -3163,3 +3174,50 @@ static bool trans_vfcmp_cond_d(DisasContext *ctx, arg_vvv_fcond *a) return true; } + +static bool trans_vbitsel_v(DisasContext *ctx, arg_vvvv *a) +{ + CHECK_SXE; + + tcg_gen_gvec_bitsel(MO_64, vreg_full_offset(a->vd), vreg_full_offset(a->va), + vreg_full_offset(a->vk), vreg_full_offset(a->vj), + 16, 16); + return true; +} + +static void gen_vbitseli(unsigned vece, TCGv_vec a, TCGv_vec b, int64_t imm) +{ + TCGv_vec t; + + t = tcg_temp_new_vec_matching(a); + tcg_gen_dupi_vec(vece, t, imm); + tcg_gen_bitsel_vec(vece, a, a, t, b); +} + +static bool trans_vbitseli_b(DisasContext *ctx, arg_vv_i *a) +{ + static const GVecGen2i op = { + .fniv = gen_vbitseli, + .fnoi = gen_helper_vbitseli_b, + .vece = MO_8, + .load_dest = true + }; + + CHECK_SXE; + + tcg_gen_gvec_2i(vreg_full_offset(a->vd), vreg_full_offset(a->vj), + 16, 16, a->imm, &op); + return true; +} + + +TRANS(vseteqz_v, gen_cv, gen_helper_vseteqz_v) +TRANS(vsetnez_v, gen_cv, gen_helper_vsetnez_v) +TRANS(vsetanyeqz_b, gen_cv, gen_helper_vsetanyeqz_b) +TRANS(vsetanyeqz_h, gen_cv, gen_helper_vsetanyeqz_h) +TRANS(vsetanyeqz_w, gen_cv, gen_helper_vsetanyeqz_w) +TRANS(vsetanyeqz_d, gen_cv, gen_helper_vsetanyeqz_d) +TRANS(vsetallnez_b, gen_cv, gen_helper_vsetallnez_b) +TRANS(vsetallnez_h, gen_cv, gen_helper_vsetallnez_h) +TRANS(vsetallnez_w, gen_cv, gen_helper_vsetallnez_w) +TRANS(vsetallnez_d, gen_cv, gen_helper_vsetallnez_d) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index d018b110cd..d8feeadc41 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -491,6 +491,7 @@ dbcl 0000 00000010 10101 ............... @i15 # &vv vd vj +&cv cd vj &vvv vd vj vk &vv_i vd vj imm &vvvv vd vj vk va @@ -500,6 +501,7 @@ dbcl 0000 00000010 10101 ............... @i15 # LSX Formats # @vv .... ........ ..... ..... vj:5 vd:5 &vv +@cv .... ........ ..... ..... vj:5 .. cd:3 &cv @vvv .... ........ ..... vk:5 vj:5 vd:5 &vvv @vv_ui3 .... ........ ..... .. imm:3 vj:5 vd:5 &vv_i @vv_ui4 .... ........ ..... . imm:4 vj:5 vd:5 &vv_i @@ -1150,3 +1152,18 @@ vslti_du 0111 00101000 10011 ..... ..... ..... @vv_ui5 vfcmp_cond_s 0000 11000101 ..... ..... ..... ..... @vvv_fcond vfcmp_cond_d 0000 11000110 ..... ..... ..... ..... @vvv_fcond + +vbitsel_v 0000 11010001 ..... ..... ..... ..... @vvvv + +vbitseli_b 0111 00111100 01 ........ ..... ..... @vv_ui8 + +vseteqz_v 0111 00101001 11001 00110 ..... 00 ... @cv +vsetnez_v 0111 00101001 11001 00111 ..... 00 ... @cv +vsetanyeqz_b 0111 00101001 11001 01000 ..... 00 ... @cv +vsetanyeqz_h 0111 00101001 11001 01001 ..... 00 ... @cv +vsetanyeqz_w 0111 00101001 11001 01010 ..... 00 ... @cv +vsetanyeqz_d 0111 00101001 11001 01011 ..... 00 ... @cv +vsetallnez_b 0111 00101001 11001 01100 ..... 00 ... @cv +vsetallnez_h 0111 00101001 11001 01101 ..... 00 ... @cv +vsetallnez_w 0111 00101001 11001 01110 ..... 00 ... @cv +vsetallnez_d 0111 00101001 11001 01111 ..... 00 ... @cv diff --git a/target/loongarch/lsx_helper.c b/target/loongarch/lsx_helper.c index 51b784e885..996312d9b2 100644 --- a/target/loongarch/lsx_helper.c +++ b/target/loongarch/lsx_helper.c @@ -2972,3 +2972,60 @@ VFCMP(vfcmp_c_s, 32, uint32_t, W, float32_compare_quiet) VFCMP(vfcmp_s_s, 32, uint32_t, W, float32_compare) VFCMP(vfcmp_c_d, 64, uint64_t, D, float64_compare_quiet) VFCMP(vfcmp_s_d, 64, uint64_t, D, float64_compare) + +void HELPER(vbitseli_b)(void *vd, void *vj, uint64_t imm, uint32_t v) +{ + int i; + VReg *Vd = (VReg *)vd; + VReg *Vj = (VReg *)vj; + + for (i = 0; i < 16; i++) { + Vd->B(i) = (~Vd->B(i) & Vj->B(i)) | (Vd->B(i) & imm); + } +} + +void HELPER(vseteqz_v)(CPULoongArchState *env, uint32_t cd, uint32_t vj) +{ + VReg *Vj = &(env->fpr[vj].vreg); + env->cf[cd & 0x7] = (Vj->Q(0) == 0); +} + +void HELPER(vsetnez_v)(CPULoongArchState *env, uint32_t cd, uint32_t vj) +{ + VReg *Vj = &(env->fpr[vj].vreg); + env->cf[cd & 0x7] = (Vj->Q(0) != 0); +} + +#define SETANYEQZ(NAME, BIT, E) \ +void HELPER(NAME)(CPULoongArchState *env, uint32_t cd, uint32_t vj) \ +{ \ + int i; \ + bool ret = false; \ + VReg *Vj = &(env->fpr[vj].vreg); \ + \ + for (i = 0; i < LSX_LEN/BIT; i++) { \ + ret |= (Vj->E(i) == 0); \ + } \ + env->cf[cd & 0x7] = ret; \ +} +SETANYEQZ(vsetanyeqz_b, 8, B) +SETANYEQZ(vsetanyeqz_h, 16, H) +SETANYEQZ(vsetanyeqz_w, 32, W) +SETANYEQZ(vsetanyeqz_d, 64, D) + +#define SETALLNEZ(NAME, BIT, E) \ +void HELPER(NAME)(CPULoongArchState *env, uint32_t cd, uint32_t vj) \ +{ \ + int i; \ + bool ret = true; \ + VReg *Vj = &(env->fpr[vj].vreg); \ + \ + for (i = 0; i < LSX_LEN/BIT; i++) { \ + ret &= (Vj->E(i) != 0); \ + } \ + env->cf[cd & 0x7] = ret; \ +} +SETALLNEZ(vsetallnez_b, 8, B) +SETALLNEZ(vsetallnez_h, 16, H) +SETALLNEZ(vsetallnez_w, 32, W) +SETALLNEZ(vsetallnez_d, 64, D)
This patch includes: - VBITSEL.V; - VBITSELI.B; - VSET{EQZ/NEZ}.V; - VSETANYEQZ.{B/H/W/D}; - VSETALLNEZ.{B/H/W/D}. Signed-off-by: Song Gao <gaosong@loongson.cn> --- target/loongarch/disas.c | 20 +++++++ target/loongarch/helper.h | 13 +++++ target/loongarch/insn_trans/trans_lsx.c.inc | 58 +++++++++++++++++++++ target/loongarch/insns.decode | 17 ++++++ target/loongarch/lsx_helper.c | 57 ++++++++++++++++++++ 5 files changed, 165 insertions(+)