mirror of https://github.com/xemu-project/xemu.git
target/arm: Vectorize integer comparison vs zero
These instructions are often used in glibc's string routines. They were the final uses of the 32-bit at a time neon helpers. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20200418162808.4680-1-richard.henderson@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
59ab136a9e
commit
6b375d3546
|
@ -275,19 +275,6 @@ DEF_HELPER_2(neon_hsub_u16, i32, i32, i32)
|
||||||
DEF_HELPER_2(neon_hsub_s32, s32, s32, s32)
|
DEF_HELPER_2(neon_hsub_s32, s32, s32, s32)
|
||||||
DEF_HELPER_2(neon_hsub_u32, i32, i32, i32)
|
DEF_HELPER_2(neon_hsub_u32, i32, i32, i32)
|
||||||
|
|
||||||
DEF_HELPER_2(neon_cgt_u8, i32, i32, i32)
|
|
||||||
DEF_HELPER_2(neon_cgt_s8, i32, i32, i32)
|
|
||||||
DEF_HELPER_2(neon_cgt_u16, i32, i32, i32)
|
|
||||||
DEF_HELPER_2(neon_cgt_s16, i32, i32, i32)
|
|
||||||
DEF_HELPER_2(neon_cgt_u32, i32, i32, i32)
|
|
||||||
DEF_HELPER_2(neon_cgt_s32, i32, i32, i32)
|
|
||||||
DEF_HELPER_2(neon_cge_u8, i32, i32, i32)
|
|
||||||
DEF_HELPER_2(neon_cge_s8, i32, i32, i32)
|
|
||||||
DEF_HELPER_2(neon_cge_u16, i32, i32, i32)
|
|
||||||
DEF_HELPER_2(neon_cge_s16, i32, i32, i32)
|
|
||||||
DEF_HELPER_2(neon_cge_u32, i32, i32, i32)
|
|
||||||
DEF_HELPER_2(neon_cge_s32, i32, i32, i32)
|
|
||||||
|
|
||||||
DEF_HELPER_2(neon_pmin_u8, i32, i32, i32)
|
DEF_HELPER_2(neon_pmin_u8, i32, i32, i32)
|
||||||
DEF_HELPER_2(neon_pmin_s8, i32, i32, i32)
|
DEF_HELPER_2(neon_pmin_s8, i32, i32, i32)
|
||||||
DEF_HELPER_2(neon_pmin_u16, i32, i32, i32)
|
DEF_HELPER_2(neon_pmin_u16, i32, i32, i32)
|
||||||
|
@ -347,9 +334,6 @@ DEF_HELPER_2(neon_mul_u16, i32, i32, i32)
|
||||||
DEF_HELPER_2(neon_tst_u8, i32, i32, i32)
|
DEF_HELPER_2(neon_tst_u8, i32, i32, i32)
|
||||||
DEF_HELPER_2(neon_tst_u16, i32, i32, i32)
|
DEF_HELPER_2(neon_tst_u16, i32, i32, i32)
|
||||||
DEF_HELPER_2(neon_tst_u32, i32, i32, i32)
|
DEF_HELPER_2(neon_tst_u32, i32, i32, i32)
|
||||||
DEF_HELPER_2(neon_ceq_u8, i32, i32, i32)
|
|
||||||
DEF_HELPER_2(neon_ceq_u16, i32, i32, i32)
|
|
||||||
DEF_HELPER_2(neon_ceq_u32, i32, i32, i32)
|
|
||||||
|
|
||||||
DEF_HELPER_1(neon_clz_u8, i32, i32)
|
DEF_HELPER_1(neon_clz_u8, i32, i32)
|
||||||
DEF_HELPER_1(neon_clz_u16, i32, i32)
|
DEF_HELPER_1(neon_clz_u16, i32, i32)
|
||||||
|
@ -686,6 +670,17 @@ DEF_HELPER_FLAGS_2(frint64_s, TCG_CALL_NO_RWG, f32, f32, ptr)
|
||||||
DEF_HELPER_FLAGS_2(frint32_d, TCG_CALL_NO_RWG, f64, f64, ptr)
|
DEF_HELPER_FLAGS_2(frint32_d, TCG_CALL_NO_RWG, f64, f64, ptr)
|
||||||
DEF_HELPER_FLAGS_2(frint64_d, TCG_CALL_NO_RWG, f64, f64, ptr)
|
DEF_HELPER_FLAGS_2(frint64_d, TCG_CALL_NO_RWG, f64, f64, ptr)
|
||||||
|
|
||||||
|
DEF_HELPER_FLAGS_3(gvec_ceq0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||||
|
DEF_HELPER_FLAGS_3(gvec_ceq0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||||
|
DEF_HELPER_FLAGS_3(gvec_clt0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||||
|
DEF_HELPER_FLAGS_3(gvec_clt0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||||
|
DEF_HELPER_FLAGS_3(gvec_cle0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||||
|
DEF_HELPER_FLAGS_3(gvec_cle0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||||
|
DEF_HELPER_FLAGS_3(gvec_cgt0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||||
|
DEF_HELPER_FLAGS_3(gvec_cgt0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||||
|
DEF_HELPER_FLAGS_3(gvec_cge0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||||
|
DEF_HELPER_FLAGS_3(gvec_cge0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||||
|
|
||||||
DEF_HELPER_FLAGS_4(gvec_sshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
DEF_HELPER_FLAGS_4(gvec_sshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||||
DEF_HELPER_FLAGS_4(gvec_sshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
DEF_HELPER_FLAGS_4(gvec_sshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||||
DEF_HELPER_FLAGS_4(gvec_ushl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
DEF_HELPER_FLAGS_4(gvec_ushl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||||
|
|
|
@ -562,24 +562,6 @@ uint32_t HELPER(neon_hsub_u32)(uint32_t src1, uint32_t src2)
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? ~0 : 0
|
|
||||||
NEON_VOP(cgt_s8, neon_s8, 4)
|
|
||||||
NEON_VOP(cgt_u8, neon_u8, 4)
|
|
||||||
NEON_VOP(cgt_s16, neon_s16, 2)
|
|
||||||
NEON_VOP(cgt_u16, neon_u16, 2)
|
|
||||||
NEON_VOP(cgt_s32, neon_s32, 1)
|
|
||||||
NEON_VOP(cgt_u32, neon_u32, 1)
|
|
||||||
#undef NEON_FN
|
|
||||||
|
|
||||||
#define NEON_FN(dest, src1, src2) dest = (src1 >= src2) ? ~0 : 0
|
|
||||||
NEON_VOP(cge_s8, neon_s8, 4)
|
|
||||||
NEON_VOP(cge_u8, neon_u8, 4)
|
|
||||||
NEON_VOP(cge_s16, neon_s16, 2)
|
|
||||||
NEON_VOP(cge_u16, neon_u16, 2)
|
|
||||||
NEON_VOP(cge_s32, neon_s32, 1)
|
|
||||||
NEON_VOP(cge_u32, neon_u32, 1)
|
|
||||||
#undef NEON_FN
|
|
||||||
|
|
||||||
#define NEON_FN(dest, src1, src2) dest = (src1 < src2) ? src1 : src2
|
#define NEON_FN(dest, src1, src2) dest = (src1 < src2) ? src1 : src2
|
||||||
NEON_POP(pmin_s8, neon_s8, 4)
|
NEON_POP(pmin_s8, neon_s8, 4)
|
||||||
NEON_POP(pmin_u8, neon_u8, 4)
|
NEON_POP(pmin_u8, neon_u8, 4)
|
||||||
|
@ -1135,12 +1117,6 @@ NEON_VOP(tst_u16, neon_u16, 2)
|
||||||
NEON_VOP(tst_u32, neon_u32, 1)
|
NEON_VOP(tst_u32, neon_u32, 1)
|
||||||
#undef NEON_FN
|
#undef NEON_FN
|
||||||
|
|
||||||
#define NEON_FN(dest, src1, src2) dest = (src1 == src2) ? -1 : 0
|
|
||||||
NEON_VOP(ceq_u8, neon_u8, 4)
|
|
||||||
NEON_VOP(ceq_u16, neon_u16, 2)
|
|
||||||
NEON_VOP(ceq_u32, neon_u32, 1)
|
|
||||||
#undef NEON_FN
|
|
||||||
|
|
||||||
/* Count Leading Sign/Zero Bits. */
|
/* Count Leading Sign/Zero Bits. */
|
||||||
static inline int do_clz8(uint8_t x)
|
static inline int do_clz8(uint8_t x)
|
||||||
{
|
{
|
||||||
|
|
|
@ -594,6 +594,14 @@ static void gen_gvec_fn4(DisasContext *s, bool is_q, int rd, int rn, int rm,
|
||||||
is_q ? 16 : 8, vec_full_reg_size(s));
|
is_q ? 16 : 8, vec_full_reg_size(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Expand a 2-operand AdvSIMD vector operation using an op descriptor. */
|
||||||
|
static void gen_gvec_op2(DisasContext *s, bool is_q, int rd,
|
||||||
|
int rn, const GVecGen2 *gvec_op)
|
||||||
|
{
|
||||||
|
tcg_gen_gvec_2(vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn),
|
||||||
|
is_q ? 16 : 8, vec_full_reg_size(s), gvec_op);
|
||||||
|
}
|
||||||
|
|
||||||
/* Expand a 2-operand + immediate AdvSIMD vector operation using
|
/* Expand a 2-operand + immediate AdvSIMD vector operation using
|
||||||
* an op descriptor.
|
* an op descriptor.
|
||||||
*/
|
*/
|
||||||
|
@ -12366,6 +12374,15 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 0x8: /* CMGT, CMGE */
|
||||||
|
gen_gvec_op2(s, is_q, rd, rn, u ? &cge0_op[size] : &cgt0_op[size]);
|
||||||
|
return;
|
||||||
|
case 0x9: /* CMEQ, CMLE */
|
||||||
|
gen_gvec_op2(s, is_q, rd, rn, u ? &cle0_op[size] : &ceq0_op[size]);
|
||||||
|
return;
|
||||||
|
case 0xa: /* CMLT */
|
||||||
|
gen_gvec_op2(s, is_q, rd, rn, &clt0_op[size]);
|
||||||
|
return;
|
||||||
case 0xb:
|
case 0xb:
|
||||||
if (u) { /* ABS, NEG */
|
if (u) { /* ABS, NEG */
|
||||||
gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_neg, size);
|
gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_neg, size);
|
||||||
|
@ -12403,29 +12420,12 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
|
||||||
for (pass = 0; pass < (is_q ? 4 : 2); pass++) {
|
for (pass = 0; pass < (is_q ? 4 : 2); pass++) {
|
||||||
TCGv_i32 tcg_op = tcg_temp_new_i32();
|
TCGv_i32 tcg_op = tcg_temp_new_i32();
|
||||||
TCGv_i32 tcg_res = tcg_temp_new_i32();
|
TCGv_i32 tcg_res = tcg_temp_new_i32();
|
||||||
TCGCond cond;
|
|
||||||
|
|
||||||
read_vec_element_i32(s, tcg_op, rn, pass, MO_32);
|
read_vec_element_i32(s, tcg_op, rn, pass, MO_32);
|
||||||
|
|
||||||
if (size == 2) {
|
if (size == 2) {
|
||||||
/* Special cases for 32 bit elements */
|
/* Special cases for 32 bit elements */
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case 0xa: /* CMLT */
|
|
||||||
/* 32 bit integer comparison against zero, result is
|
|
||||||
* test ? (2^32 - 1) : 0. We implement via setcond(test)
|
|
||||||
* and inverting.
|
|
||||||
*/
|
|
||||||
cond = TCG_COND_LT;
|
|
||||||
do_cmop:
|
|
||||||
tcg_gen_setcondi_i32(cond, tcg_res, tcg_op, 0);
|
|
||||||
tcg_gen_neg_i32(tcg_res, tcg_res);
|
|
||||||
break;
|
|
||||||
case 0x8: /* CMGT, CMGE */
|
|
||||||
cond = u ? TCG_COND_GE : TCG_COND_GT;
|
|
||||||
goto do_cmop;
|
|
||||||
case 0x9: /* CMEQ, CMLE */
|
|
||||||
cond = u ? TCG_COND_LE : TCG_COND_EQ;
|
|
||||||
goto do_cmop;
|
|
||||||
case 0x4: /* CLS */
|
case 0x4: /* CLS */
|
||||||
if (u) {
|
if (u) {
|
||||||
tcg_gen_clzi_i32(tcg_res, tcg_op, 32);
|
tcg_gen_clzi_i32(tcg_res, tcg_op, 32);
|
||||||
|
@ -12522,36 +12522,6 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
|
||||||
genfn(tcg_res, cpu_env, tcg_op);
|
genfn(tcg_res, cpu_env, tcg_op);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x8: /* CMGT, CMGE */
|
|
||||||
case 0x9: /* CMEQ, CMLE */
|
|
||||||
case 0xa: /* CMLT */
|
|
||||||
{
|
|
||||||
static NeonGenTwoOpFn * const fns[3][2] = {
|
|
||||||
{ gen_helper_neon_cgt_s8, gen_helper_neon_cgt_s16 },
|
|
||||||
{ gen_helper_neon_cge_s8, gen_helper_neon_cge_s16 },
|
|
||||||
{ gen_helper_neon_ceq_u8, gen_helper_neon_ceq_u16 },
|
|
||||||
};
|
|
||||||
NeonGenTwoOpFn *genfn;
|
|
||||||
int comp;
|
|
||||||
bool reverse;
|
|
||||||
TCGv_i32 tcg_zero = tcg_const_i32(0);
|
|
||||||
|
|
||||||
/* comp = index into [CMGT, CMGE, CMEQ, CMLE, CMLT] */
|
|
||||||
comp = (opcode - 0x8) * 2 + u;
|
|
||||||
/* ...but LE, LT are implemented as reverse GE, GT */
|
|
||||||
reverse = (comp > 2);
|
|
||||||
if (reverse) {
|
|
||||||
comp = 4 - comp;
|
|
||||||
}
|
|
||||||
genfn = fns[comp][size];
|
|
||||||
if (reverse) {
|
|
||||||
genfn(tcg_res, tcg_zero, tcg_op);
|
|
||||||
} else {
|
|
||||||
genfn(tcg_res, tcg_op, tcg_zero);
|
|
||||||
}
|
|
||||||
tcg_temp_free_i32(tcg_zero);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x4: /* CLS, CLZ */
|
case 0x4: /* CLS, CLZ */
|
||||||
if (u) {
|
if (u) {
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
|
|
|
@ -3917,6 +3917,205 @@ static int do_v81_helper(DisasContext *s, gen_helper_gvec_3_ptr *fn,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gen_ceq0_i32(TCGv_i32 d, TCGv_i32 a)
|
||||||
|
{
|
||||||
|
tcg_gen_setcondi_i32(TCG_COND_EQ, d, a, 0);
|
||||||
|
tcg_gen_neg_i32(d, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_ceq0_i64(TCGv_i64 d, TCGv_i64 a)
|
||||||
|
{
|
||||||
|
tcg_gen_setcondi_i64(TCG_COND_EQ, d, a, 0);
|
||||||
|
tcg_gen_neg_i64(d, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_ceq0_vec(unsigned vece, TCGv_vec d, TCGv_vec a)
|
||||||
|
{
|
||||||
|
TCGv_vec zero = tcg_const_zeros_vec_matching(d);
|
||||||
|
tcg_gen_cmp_vec(TCG_COND_EQ, vece, d, a, zero);
|
||||||
|
tcg_temp_free_vec(zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TCGOpcode vecop_list_cmp[] = {
|
||||||
|
INDEX_op_cmp_vec, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
const GVecGen2 ceq0_op[4] = {
|
||||||
|
{ .fno = gen_helper_gvec_ceq0_b,
|
||||||
|
.fniv = gen_ceq0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.vece = MO_8 },
|
||||||
|
{ .fno = gen_helper_gvec_ceq0_h,
|
||||||
|
.fniv = gen_ceq0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.vece = MO_16 },
|
||||||
|
{ .fni4 = gen_ceq0_i32,
|
||||||
|
.fniv = gen_ceq0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.vece = MO_32 },
|
||||||
|
{ .fni8 = gen_ceq0_i64,
|
||||||
|
.fniv = gen_ceq0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.prefer_i64 = TCG_TARGET_REG_BITS == 64,
|
||||||
|
.vece = MO_64 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void gen_cle0_i32(TCGv_i32 d, TCGv_i32 a)
|
||||||
|
{
|
||||||
|
tcg_gen_setcondi_i32(TCG_COND_LE, d, a, 0);
|
||||||
|
tcg_gen_neg_i32(d, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_cle0_i64(TCGv_i64 d, TCGv_i64 a)
|
||||||
|
{
|
||||||
|
tcg_gen_setcondi_i64(TCG_COND_LE, d, a, 0);
|
||||||
|
tcg_gen_neg_i64(d, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_cle0_vec(unsigned vece, TCGv_vec d, TCGv_vec a)
|
||||||
|
{
|
||||||
|
TCGv_vec zero = tcg_const_zeros_vec_matching(d);
|
||||||
|
tcg_gen_cmp_vec(TCG_COND_LE, vece, d, a, zero);
|
||||||
|
tcg_temp_free_vec(zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
const GVecGen2 cle0_op[4] = {
|
||||||
|
{ .fno = gen_helper_gvec_cle0_b,
|
||||||
|
.fniv = gen_cle0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.vece = MO_8 },
|
||||||
|
{ .fno = gen_helper_gvec_cle0_h,
|
||||||
|
.fniv = gen_cle0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.vece = MO_16 },
|
||||||
|
{ .fni4 = gen_cle0_i32,
|
||||||
|
.fniv = gen_cle0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.vece = MO_32 },
|
||||||
|
{ .fni8 = gen_cle0_i64,
|
||||||
|
.fniv = gen_cle0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.prefer_i64 = TCG_TARGET_REG_BITS == 64,
|
||||||
|
.vece = MO_64 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void gen_cge0_i32(TCGv_i32 d, TCGv_i32 a)
|
||||||
|
{
|
||||||
|
tcg_gen_setcondi_i32(TCG_COND_GE, d, a, 0);
|
||||||
|
tcg_gen_neg_i32(d, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_cge0_i64(TCGv_i64 d, TCGv_i64 a)
|
||||||
|
{
|
||||||
|
tcg_gen_setcondi_i64(TCG_COND_GE, d, a, 0);
|
||||||
|
tcg_gen_neg_i64(d, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_cge0_vec(unsigned vece, TCGv_vec d, TCGv_vec a)
|
||||||
|
{
|
||||||
|
TCGv_vec zero = tcg_const_zeros_vec_matching(d);
|
||||||
|
tcg_gen_cmp_vec(TCG_COND_GE, vece, d, a, zero);
|
||||||
|
tcg_temp_free_vec(zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
const GVecGen2 cge0_op[4] = {
|
||||||
|
{ .fno = gen_helper_gvec_cge0_b,
|
||||||
|
.fniv = gen_cge0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.vece = MO_8 },
|
||||||
|
{ .fno = gen_helper_gvec_cge0_h,
|
||||||
|
.fniv = gen_cge0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.vece = MO_16 },
|
||||||
|
{ .fni4 = gen_cge0_i32,
|
||||||
|
.fniv = gen_cge0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.vece = MO_32 },
|
||||||
|
{ .fni8 = gen_cge0_i64,
|
||||||
|
.fniv = gen_cge0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.prefer_i64 = TCG_TARGET_REG_BITS == 64,
|
||||||
|
.vece = MO_64 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void gen_clt0_i32(TCGv_i32 d, TCGv_i32 a)
|
||||||
|
{
|
||||||
|
tcg_gen_setcondi_i32(TCG_COND_LT, d, a, 0);
|
||||||
|
tcg_gen_neg_i32(d, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_clt0_i64(TCGv_i64 d, TCGv_i64 a)
|
||||||
|
{
|
||||||
|
tcg_gen_setcondi_i64(TCG_COND_LT, d, a, 0);
|
||||||
|
tcg_gen_neg_i64(d, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_clt0_vec(unsigned vece, TCGv_vec d, TCGv_vec a)
|
||||||
|
{
|
||||||
|
TCGv_vec zero = tcg_const_zeros_vec_matching(d);
|
||||||
|
tcg_gen_cmp_vec(TCG_COND_LT, vece, d, a, zero);
|
||||||
|
tcg_temp_free_vec(zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
const GVecGen2 clt0_op[4] = {
|
||||||
|
{ .fno = gen_helper_gvec_clt0_b,
|
||||||
|
.fniv = gen_clt0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.vece = MO_8 },
|
||||||
|
{ .fno = gen_helper_gvec_clt0_h,
|
||||||
|
.fniv = gen_clt0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.vece = MO_16 },
|
||||||
|
{ .fni4 = gen_clt0_i32,
|
||||||
|
.fniv = gen_clt0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.vece = MO_32 },
|
||||||
|
{ .fni8 = gen_clt0_i64,
|
||||||
|
.fniv = gen_clt0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.prefer_i64 = TCG_TARGET_REG_BITS == 64,
|
||||||
|
.vece = MO_64 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void gen_cgt0_i32(TCGv_i32 d, TCGv_i32 a)
|
||||||
|
{
|
||||||
|
tcg_gen_setcondi_i32(TCG_COND_GT, d, a, 0);
|
||||||
|
tcg_gen_neg_i32(d, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_cgt0_i64(TCGv_i64 d, TCGv_i64 a)
|
||||||
|
{
|
||||||
|
tcg_gen_setcondi_i64(TCG_COND_GT, d, a, 0);
|
||||||
|
tcg_gen_neg_i64(d, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_cgt0_vec(unsigned vece, TCGv_vec d, TCGv_vec a)
|
||||||
|
{
|
||||||
|
TCGv_vec zero = tcg_const_zeros_vec_matching(d);
|
||||||
|
tcg_gen_cmp_vec(TCG_COND_GT, vece, d, a, zero);
|
||||||
|
tcg_temp_free_vec(zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
const GVecGen2 cgt0_op[4] = {
|
||||||
|
{ .fno = gen_helper_gvec_cgt0_b,
|
||||||
|
.fniv = gen_cgt0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.vece = MO_8 },
|
||||||
|
{ .fno = gen_helper_gvec_cgt0_h,
|
||||||
|
.fniv = gen_cgt0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.vece = MO_16 },
|
||||||
|
{ .fni4 = gen_cgt0_i32,
|
||||||
|
.fniv = gen_cgt0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.vece = MO_32 },
|
||||||
|
{ .fni8 = gen_cgt0_i64,
|
||||||
|
.fniv = gen_cgt0_vec,
|
||||||
|
.opt_opc = vecop_list_cmp,
|
||||||
|
.prefer_i64 = TCG_TARGET_REG_BITS == 64,
|
||||||
|
.vece = MO_64 },
|
||||||
|
};
|
||||||
|
|
||||||
static void gen_ssra8_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
|
static void gen_ssra8_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
|
||||||
{
|
{
|
||||||
tcg_gen_vec_sar8i_i64(a, a, shift);
|
tcg_gen_vec_sar8i_i64(a, a, shift);
|
||||||
|
@ -6481,6 +6680,27 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
||||||
tcg_gen_gvec_abs(size, rd_ofs, rm_ofs, vec_size, vec_size);
|
tcg_gen_gvec_abs(size, rd_ofs, rm_ofs, vec_size, vec_size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NEON_2RM_VCEQ0:
|
||||||
|
tcg_gen_gvec_2(rd_ofs, rm_ofs, vec_size,
|
||||||
|
vec_size, &ceq0_op[size]);
|
||||||
|
break;
|
||||||
|
case NEON_2RM_VCGT0:
|
||||||
|
tcg_gen_gvec_2(rd_ofs, rm_ofs, vec_size,
|
||||||
|
vec_size, &cgt0_op[size]);
|
||||||
|
break;
|
||||||
|
case NEON_2RM_VCLE0:
|
||||||
|
tcg_gen_gvec_2(rd_ofs, rm_ofs, vec_size,
|
||||||
|
vec_size, &cle0_op[size]);
|
||||||
|
break;
|
||||||
|
case NEON_2RM_VCGE0:
|
||||||
|
tcg_gen_gvec_2(rd_ofs, rm_ofs, vec_size,
|
||||||
|
vec_size, &cge0_op[size]);
|
||||||
|
break;
|
||||||
|
case NEON_2RM_VCLT0:
|
||||||
|
tcg_gen_gvec_2(rd_ofs, rm_ofs, vec_size,
|
||||||
|
vec_size, &clt0_op[size]);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
elementwise:
|
elementwise:
|
||||||
for (pass = 0; pass < (q ? 4 : 2); pass++) {
|
for (pass = 0; pass < (q ? 4 : 2); pass++) {
|
||||||
|
@ -6543,42 +6763,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
||||||
default: abort();
|
default: abort();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NEON_2RM_VCGT0: case NEON_2RM_VCLE0:
|
|
||||||
tmp2 = tcg_const_i32(0);
|
|
||||||
switch(size) {
|
|
||||||
case 0: gen_helper_neon_cgt_s8(tmp, tmp, tmp2); break;
|
|
||||||
case 1: gen_helper_neon_cgt_s16(tmp, tmp, tmp2); break;
|
|
||||||
case 2: gen_helper_neon_cgt_s32(tmp, tmp, tmp2); break;
|
|
||||||
default: abort();
|
|
||||||
}
|
|
||||||
tcg_temp_free_i32(tmp2);
|
|
||||||
if (op == NEON_2RM_VCLE0) {
|
|
||||||
tcg_gen_not_i32(tmp, tmp);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NEON_2RM_VCGE0: case NEON_2RM_VCLT0:
|
|
||||||
tmp2 = tcg_const_i32(0);
|
|
||||||
switch(size) {
|
|
||||||
case 0: gen_helper_neon_cge_s8(tmp, tmp, tmp2); break;
|
|
||||||
case 1: gen_helper_neon_cge_s16(tmp, tmp, tmp2); break;
|
|
||||||
case 2: gen_helper_neon_cge_s32(tmp, tmp, tmp2); break;
|
|
||||||
default: abort();
|
|
||||||
}
|
|
||||||
tcg_temp_free_i32(tmp2);
|
|
||||||
if (op == NEON_2RM_VCLT0) {
|
|
||||||
tcg_gen_not_i32(tmp, tmp);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NEON_2RM_VCEQ0:
|
|
||||||
tmp2 = tcg_const_i32(0);
|
|
||||||
switch(size) {
|
|
||||||
case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
|
|
||||||
case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
|
|
||||||
case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
|
|
||||||
default: abort();
|
|
||||||
}
|
|
||||||
tcg_temp_free_i32(tmp2);
|
|
||||||
break;
|
|
||||||
case NEON_2RM_VCGT0_F:
|
case NEON_2RM_VCGT0_F:
|
||||||
{
|
{
|
||||||
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||||
|
|
|
@ -275,6 +275,11 @@ static inline void gen_swstep_exception(DisasContext *s, int isv, int ex)
|
||||||
uint64_t vfp_expand_imm(int size, uint8_t imm8);
|
uint64_t vfp_expand_imm(int size, uint8_t imm8);
|
||||||
|
|
||||||
/* Vector operations shared between ARM and AArch64. */
|
/* Vector operations shared between ARM and AArch64. */
|
||||||
|
extern const GVecGen2 ceq0_op[4];
|
||||||
|
extern const GVecGen2 clt0_op[4];
|
||||||
|
extern const GVecGen2 cgt0_op[4];
|
||||||
|
extern const GVecGen2 cle0_op[4];
|
||||||
|
extern const GVecGen2 cge0_op[4];
|
||||||
extern const GVecGen3 mla_op[4];
|
extern const GVecGen3 mla_op[4];
|
||||||
extern const GVecGen3 mls_op[4];
|
extern const GVecGen3 mls_op[4];
|
||||||
extern const GVecGen3 cmtst_op[4];
|
extern const GVecGen3 cmtst_op[4];
|
||||||
|
|
|
@ -1257,3 +1257,28 @@ void HELPER(sve2_pmull_h)(void *vd, void *vn, void *vm, uint32_t desc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define DO_CMP0(NAME, TYPE, OP) \
|
||||||
|
void HELPER(NAME)(void *vd, void *vn, uint32_t desc) \
|
||||||
|
{ \
|
||||||
|
intptr_t i, opr_sz = simd_oprsz(desc); \
|
||||||
|
for (i = 0; i < opr_sz; i += sizeof(TYPE)) { \
|
||||||
|
TYPE nn = *(TYPE *)(vn + i); \
|
||||||
|
*(TYPE *)(vd + i) = -(nn OP 0); \
|
||||||
|
} \
|
||||||
|
clear_tail(vd, opr_sz, simd_maxsz(desc)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
DO_CMP0(gvec_ceq0_b, int8_t, ==)
|
||||||
|
DO_CMP0(gvec_clt0_b, int8_t, <)
|
||||||
|
DO_CMP0(gvec_cle0_b, int8_t, <=)
|
||||||
|
DO_CMP0(gvec_cgt0_b, int8_t, >)
|
||||||
|
DO_CMP0(gvec_cge0_b, int8_t, >=)
|
||||||
|
|
||||||
|
DO_CMP0(gvec_ceq0_h, int16_t, ==)
|
||||||
|
DO_CMP0(gvec_clt0_h, int16_t, <)
|
||||||
|
DO_CMP0(gvec_cle0_h, int16_t, <=)
|
||||||
|
DO_CMP0(gvec_cgt0_h, int16_t, >)
|
||||||
|
DO_CMP0(gvec_cge0_h, int16_t, >=)
|
||||||
|
|
||||||
|
#undef DO_CMP0
|
||||||
|
|
Loading…
Reference in New Issue