target/arm: Introduce gen_gvec_cls, gen_gvec_clz

Add gvec interfaces for CLS and CLZ operations.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20241211163036.2297116-38-richard.henderson@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Richard Henderson 2024-12-11 10:30:04 -06:00 committed by Peter Maydell
parent 9187b72cff
commit 4fedfb483b
4 changed files with 49 additions and 49 deletions

View File

@ -2358,3 +2358,38 @@ void gen_gvec_urhadd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
assert(vece <= MO_32); assert(vece <= MO_32);
tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &g[vece]); tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &g[vece]);
} }
void gen_gvec_cls(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
uint32_t opr_sz, uint32_t max_sz)
{
static const GVecGen2 g[] = {
{ .fni4 = gen_helper_neon_cls_s8,
.vece = MO_8 },
{ .fni4 = gen_helper_neon_cls_s16,
.vece = MO_16 },
{ .fni4 = tcg_gen_clrsb_i32,
.vece = MO_32 },
};
assert(vece <= MO_32);
tcg_gen_gvec_2(rd_ofs, rn_ofs, opr_sz, max_sz, &g[vece]);
}
static void gen_clz32_i32(TCGv_i32 d, TCGv_i32 n)
{
tcg_gen_clzi_i32(d, n, 32);
}
void gen_gvec_clz(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
uint32_t opr_sz, uint32_t max_sz)
{
static const GVecGen2 g[] = {
{ .fni4 = gen_helper_neon_clz_u8,
.vece = MO_8 },
{ .fni4 = gen_helper_neon_clz_u16,
.vece = MO_16 },
{ .fni4 = gen_clz32_i32,
.vece = MO_32 },
};
assert(vece <= MO_32);
tcg_gen_gvec_2(rd_ofs, rn_ofs, opr_sz, max_sz, &g[vece]);
}

View File

@ -10321,6 +10321,13 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
} }
switch (opcode) { switch (opcode) {
case 0x4: /* CLZ, CLS */
if (u) {
gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_clz, size);
} else {
gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_cls, size);
}
return;
case 0x5: case 0x5:
if (u && size == 0) { /* NOT */ if (u && size == 0) { /* NOT */
gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_not, 0); gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_not, 0);
@ -10379,13 +10386,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
if (size == 2) { if (size == 2) {
/* Special cases for 32 bit elements */ /* Special cases for 32 bit elements */
switch (opcode) { switch (opcode) {
case 0x4: /* CLS */
if (u) {
tcg_gen_clzi_i32(tcg_res, tcg_op, 32);
} else {
tcg_gen_clrsb_i32(tcg_res, tcg_op);
}
break;
case 0x2f: /* FABS */ case 0x2f: /* FABS */
gen_vfp_abss(tcg_res, tcg_op); gen_vfp_abss(tcg_res, tcg_op);
break; break;
@ -10450,21 +10450,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
gen_helper_neon_cnt_u8(tcg_res, tcg_op); gen_helper_neon_cnt_u8(tcg_res, tcg_op);
} }
break; break;
case 0x4: /* CLS, CLZ */
if (u) {
if (size == 0) {
gen_helper_neon_clz_u8(tcg_res, tcg_op);
} else {
gen_helper_neon_clz_u16(tcg_res, tcg_op);
}
} else {
if (size == 0) {
gen_helper_neon_cls_s8(tcg_res, tcg_op);
} else {
gen_helper_neon_cls_s16(tcg_res, tcg_op);
}
}
break;
default: default:
case 0x7: /* SQABS, SQNEG */ case 0x7: /* SQABS, SQNEG */
g_assert_not_reached(); g_assert_not_reached();

View File

@ -3120,6 +3120,8 @@ DO_2MISC_VEC(VCGT0, gen_gvec_cgt0)
DO_2MISC_VEC(VCLE0, gen_gvec_cle0) DO_2MISC_VEC(VCLE0, gen_gvec_cle0)
DO_2MISC_VEC(VCGE0, gen_gvec_cge0) DO_2MISC_VEC(VCGE0, gen_gvec_cge0)
DO_2MISC_VEC(VCLT0, gen_gvec_clt0) DO_2MISC_VEC(VCLT0, gen_gvec_clt0)
DO_2MISC_VEC(VCLS, gen_gvec_cls)
DO_2MISC_VEC(VCLZ, gen_gvec_clz)
static bool trans_VMVN(DisasContext *s, arg_2misc *a) static bool trans_VMVN(DisasContext *s, arg_2misc *a)
{ {
@ -3227,33 +3229,6 @@ static bool trans_VREV16(DisasContext *s, arg_2misc *a)
return do_2misc(s, a, gen_rev16); return do_2misc(s, a, gen_rev16);
} }
static bool trans_VCLS(DisasContext *s, arg_2misc *a)
{
static NeonGenOneOpFn * const fn[] = {
gen_helper_neon_cls_s8,
gen_helper_neon_cls_s16,
gen_helper_neon_cls_s32,
NULL,
};
return do_2misc(s, a, fn[a->size]);
}
static void do_VCLZ_32(TCGv_i32 rd, TCGv_i32 rm)
{
tcg_gen_clzi_i32(rd, rm, 32);
}
static bool trans_VCLZ(DisasContext *s, arg_2misc *a)
{
static NeonGenOneOpFn * const fn[] = {
gen_helper_neon_clz_u8,
gen_helper_neon_clz_u16,
do_VCLZ_32,
NULL,
};
return do_2misc(s, a, fn[a->size]);
}
static bool trans_VCNT(DisasContext *s, arg_2misc *a) static bool trans_VCNT(DisasContext *s, arg_2misc *a)
{ {
if (a->size != 0) { if (a->size != 0) {

View File

@ -578,6 +578,11 @@ void gen_gvec_umaxp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
void gen_gvec_uminp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, void gen_gvec_uminp(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz);
void gen_gvec_cls(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
uint32_t opr_sz, uint32_t max_sz);
void gen_gvec_clz(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
uint32_t opr_sz, uint32_t max_sz);
/* /*
* Forward to the isar_feature_* tests given a DisasContext pointer. * Forward to the isar_feature_* tests given a DisasContext pointer.
*/ */