From 9f7dc6a8910e217777e52bbb349f79da5c95565e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 16 Jan 2014 13:13:45 +0000 Subject: target-arm: A64: Add integer ops from SIMD 3-same group Add some of the integer operations in the SIMD 3-same group: specifically, the comparisons, addition and subtraction. Signed-off-by: Peter Maydell --- target-arm/translate-a64.c | 141 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 140 insertions(+), 1 deletion(-) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 82f8e8e479..893c05bacc 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -6009,7 +6009,146 @@ static void disas_simd_3same_float(DisasContext *s, uint32_t insn) /* Integer op subgroup of C3.6.16. */ static void disas_simd_3same_int(DisasContext *s, uint32_t insn) { - unsupported_encoding(s, insn); + int is_q = extract32(insn, 30, 1); + int u = extract32(insn, 29, 1); + int size = extract32(insn, 22, 2); + int opcode = extract32(insn, 11, 5); + int rm = extract32(insn, 16, 5); + int rn = extract32(insn, 5, 5); + int rd = extract32(insn, 0, 5); + int pass; + + switch (opcode) { + case 0x13: /* MUL, PMUL */ + if (u && size != 0) { + unallocated_encoding(s); + return; + } + /* fall through */ + case 0x0: /* SHADD, UHADD */ + case 0x2: /* SRHADD, URHADD */ + case 0x4: /* SHSUB, UHSUB */ + case 0xc: /* SMAX, UMAX */ + case 0xd: /* SMIN, UMIN */ + case 0xe: /* SABD, UABD */ + case 0xf: /* SABA, UABA */ + case 0x12: /* MLA, MLS */ + if (size == 3) { + unallocated_encoding(s); + return; + } + break; + case 0x1: /* SQADD */ + case 0x5: /* SQSUB */ + case 0x8: /* SSHL, USHL */ + case 0x9: /* SQSHL, UQSHL */ + case 0xa: /* SRSHL, URSHL */ + case 0xb: /* SQRSHL, UQRSHL */ + if (size == 3 && !is_q) { + unallocated_encoding(s); + return; + } + unsupported_encoding(s, insn); + return; + default: + if (size == 3 && !is_q) { + unallocated_encoding(s); + return; + } + break; + } + + if (size == 3) { + for (pass = 0; pass < (is_q ? 2 : 1); pass++) { + TCGv_i64 tcg_op1 = tcg_temp_new_i64(); + TCGv_i64 tcg_op2 = tcg_temp_new_i64(); + TCGv_i64 tcg_res = tcg_temp_new_i64(); + + read_vec_element(s, tcg_op1, rn, pass, MO_64); + read_vec_element(s, tcg_op2, rm, pass, MO_64); + + handle_3same_64(s, opcode, u, tcg_res, tcg_op1, tcg_op2); + + write_vec_element(s, tcg_res, rd, pass, MO_64); + + tcg_temp_free_i64(tcg_res); + tcg_temp_free_i64(tcg_op1); + tcg_temp_free_i64(tcg_op2); + } + } else { + for (pass = 0; pass < (is_q ? 4 : 2); pass++) { + TCGv_i32 tcg_op1 = tcg_temp_new_i32(); + TCGv_i32 tcg_op2 = tcg_temp_new_i32(); + TCGv_i32 tcg_res = tcg_temp_new_i32(); + TCGv_i64 tcg_tmp = tcg_temp_new_i64(); + typedef void NeonGenFn(TCGv_i32, TCGv_i32, TCGv_i32); + NeonGenFn *genfn; + + read_vec_element(s, tcg_tmp, rn, pass, MO_32); + tcg_gen_trunc_i64_i32(tcg_op1, tcg_tmp); + read_vec_element(s, tcg_tmp, rm, pass, MO_32); + tcg_gen_trunc_i64_i32(tcg_op2, tcg_tmp); + + switch (opcode) { + case 0x6: /* CMGT, CMHI */ + { + NeonGenFn *ceqtstfns[3][2] = { + { gen_helper_neon_cgt_s8, gen_helper_neon_cgt_u8 }, + { gen_helper_neon_cgt_s16, gen_helper_neon_cgt_u16 }, + { gen_helper_neon_cgt_s32, gen_helper_neon_cgt_u32 }, + }; + genfn = ceqtstfns[size][u]; + break; + } + case 0x7: /* CMGE, CMHS */ + { + NeonGenFn *ceqtstfns[3][2] = { + { gen_helper_neon_cge_s8, gen_helper_neon_cge_u8 }, + { gen_helper_neon_cge_s16, gen_helper_neon_cge_u16 }, + { gen_helper_neon_cge_s32, gen_helper_neon_cge_u32 }, + }; + genfn = ceqtstfns[size][u]; + break; + } + case 0x10: /* ADD, SUB */ + { + NeonGenFn *addfns[3][2] = { + { gen_helper_neon_add_u8, gen_helper_neon_sub_u8 }, + { gen_helper_neon_add_u16, gen_helper_neon_sub_u16 }, + { tcg_gen_add_i32, tcg_gen_sub_i32 }, + }; + genfn = addfns[size][u]; + break; + } + case 0x11: /* CMTST, CMEQ */ + { + NeonGenFn *ceqtstfns[3][2] = { + { gen_helper_neon_tst_u8, gen_helper_neon_ceq_u8 }, + { gen_helper_neon_tst_u16, gen_helper_neon_ceq_u16 }, + { gen_helper_neon_tst_u32, gen_helper_neon_ceq_u32 }, + }; + genfn = ceqtstfns[size][u]; + break; + } + default: + g_assert_not_reached(); + } + + genfn(tcg_res, tcg_op1, tcg_op2); + + tcg_gen_extu_i32_i64(tcg_tmp, tcg_res); + write_vec_element(s, tcg_tmp, rd, pass, MO_32); + + tcg_temp_free_i32(tcg_res); + tcg_temp_free_i32(tcg_op1); + tcg_temp_free_i32(tcg_op2); + tcg_temp_free_i64(tcg_tmp); + } + } + + if (!is_q) { + clear_vec_high(s, rd); + } } /* C3.6.16 AdvSIMD three same -- cgit v1.2.3