diff options
Diffstat (limited to 'target/arm/translate.c')
-rw-r--r-- | target/arm/translate.c | 539 |
1 files changed, 22 insertions, 517 deletions
diff --git a/target/arm/translate.c b/target/arm/translate.c index c8296116d4..bcdfec34d2 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3011,29 +3011,6 @@ static inline void gen_neon_rsb(int size, TCGv_i32 t0, TCGv_i32 t1) } } -#define GEN_NEON_INTEGER_OP_ENV(name) do { \ - switch ((size << 1) | u) { \ - case 0: \ - gen_helper_neon_##name##_s8(tmp, cpu_env, tmp, tmp2); \ - break; \ - case 1: \ - gen_helper_neon_##name##_u8(tmp, cpu_env, tmp, tmp2); \ - break; \ - case 2: \ - gen_helper_neon_##name##_s16(tmp, cpu_env, tmp, tmp2); \ - break; \ - case 3: \ - gen_helper_neon_##name##_u16(tmp, cpu_env, tmp, tmp2); \ - break; \ - case 4: \ - gen_helper_neon_##name##_s32(tmp, cpu_env, tmp, tmp2); \ - break; \ - case 5: \ - gen_helper_neon_##name##_u32(tmp, cpu_env, tmp, tmp2); \ - break; \ - default: return 1; \ - }} while (0) - static TCGv_i32 neon_load_scratch(int scratch) { TCGv_i32 tmp = tcg_temp_new_i32(); @@ -3224,40 +3201,6 @@ static inline void gen_neon_unarrow_sats(int size, TCGv_i32 dest, TCGv_i64 src) } } -static inline void gen_neon_shift_narrow(int size, TCGv_i32 var, TCGv_i32 shift, - int q, int u) -{ - if (q) { - if (u) { - switch (size) { - case 1: gen_helper_neon_rshl_u16(var, var, shift); break; - case 2: gen_helper_neon_rshl_u32(var, var, shift); break; - default: abort(); - } - } else { - switch (size) { - case 1: gen_helper_neon_rshl_s16(var, var, shift); break; - case 2: gen_helper_neon_rshl_s32(var, var, shift); break; - default: abort(); - } - } - } else { - if (u) { - switch (size) { - case 1: gen_helper_neon_shl_u16(var, var, shift); break; - case 2: gen_ushl_i32(var, var, shift); break; - default: abort(); - } - } else { - switch (size) { - case 1: gen_helper_neon_shl_s16(var, var, shift); break; - case 2: gen_sshl_i32(var, var, shift); break; - default: abort(); - } - } - } -} - static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u) { if (u) { @@ -5250,14 +5193,12 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) int q; int rd, rn, rm, rd_ofs, rn_ofs, rm_ofs; int size; - int shift; int pass; - int count; int u; int vec_size; uint32_t imm; TCGv_i32 tmp, tmp2, tmp3, tmp4, tmp5; - TCGv_ptr ptr1, ptr2; + TCGv_ptr ptr1; TCGv_i64 tmp64; if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { @@ -5291,433 +5232,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) /* Three register same length: handled by decodetree */ return 1; } else if (insn & (1 << 4)) { - if ((insn & 0x00380080) != 0) { - /* Two registers and shift. */ - op = (insn >> 8) & 0xf; - if (insn & (1 << 7)) { - /* 64-bit shift. */ - if (op > 7) { - return 1; - } - size = 3; - } else { - size = 2; - while ((insn & (1 << (size + 19))) == 0) - size--; - } - shift = (insn >> 16) & ((1 << (3 + size)) - 1); - if (op < 8) { - /* Shift by immediate: - VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU. */ - if (q && ((rd | rm) & 1)) { - return 1; - } - if (!u && (op == 4 || op == 6)) { - return 1; - } - /* Right shifts are encoded as N - shift, where N is the - element size in bits. */ - if (op <= 4) { - shift = shift - (1 << (size + 3)); - } - - switch (op) { - case 0: /* VSHR */ - /* Right shift comes here negative. */ - shift = -shift; - /* Shifts larger than the element size are architecturally - * valid. Unsigned results in all zeros; signed results - * in all sign bits. - */ - if (!u) { - tcg_gen_gvec_sari(size, rd_ofs, rm_ofs, - MIN(shift, (8 << size) - 1), - vec_size, vec_size); - } else if (shift >= 8 << size) { - tcg_gen_gvec_dup_imm(MO_8, rd_ofs, vec_size, - vec_size, 0); - } else { - tcg_gen_gvec_shri(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } - return 0; - - case 1: /* VSRA */ - /* Right shift comes here negative. */ - shift = -shift; - if (u) { - gen_gvec_usra(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } else { - gen_gvec_ssra(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } - return 0; - - case 2: /* VRSHR */ - /* Right shift comes here negative. */ - shift = -shift; - if (u) { - gen_gvec_urshr(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } else { - gen_gvec_srshr(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } - return 0; - - case 3: /* VRSRA */ - /* Right shift comes here negative. */ - shift = -shift; - if (u) { - gen_gvec_ursra(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } else { - gen_gvec_srsra(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } - return 0; - - case 4: /* VSRI */ - if (!u) { - return 1; - } - /* Right shift comes here negative. */ - shift = -shift; - gen_gvec_sri(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - return 0; - - case 5: /* VSHL, VSLI */ - if (u) { /* VSLI */ - gen_gvec_sli(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } else { /* VSHL */ - tcg_gen_gvec_shli(size, rd_ofs, rm_ofs, shift, - vec_size, vec_size); - } - return 0; - } - - if (size == 3) { - count = q + 1; - } else { - count = q ? 4: 2; - } - - /* To avoid excessive duplication of ops we implement shift - * by immediate using the variable shift operations. - */ - imm = dup_const(size, shift); - - for (pass = 0; pass < count; pass++) { - if (size == 3) { - neon_load_reg64(cpu_V0, rm + pass); - tcg_gen_movi_i64(cpu_V1, imm); - switch (op) { - case 6: /* VQSHLU */ - gen_helper_neon_qshlu_s64(cpu_V0, cpu_env, - cpu_V0, cpu_V1); - break; - case 7: /* VQSHL */ - if (u) { - gen_helper_neon_qshl_u64(cpu_V0, cpu_env, - cpu_V0, cpu_V1); - } else { - gen_helper_neon_qshl_s64(cpu_V0, cpu_env, - cpu_V0, cpu_V1); - } - break; - default: - g_assert_not_reached(); - } - neon_store_reg64(cpu_V0, rd + pass); - } else { /* size < 3 */ - /* Operands in T0 and T1. */ - tmp = neon_load_reg(rm, pass); - tmp2 = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp2, imm); - switch (op) { - case 6: /* VQSHLU */ - switch (size) { - case 0: - gen_helper_neon_qshlu_s8(tmp, cpu_env, - tmp, tmp2); - break; - case 1: - gen_helper_neon_qshlu_s16(tmp, cpu_env, - tmp, tmp2); - break; - case 2: - gen_helper_neon_qshlu_s32(tmp, cpu_env, - tmp, tmp2); - break; - default: - abort(); - } - break; - case 7: /* VQSHL */ - GEN_NEON_INTEGER_OP_ENV(qshl); - break; - default: - g_assert_not_reached(); - } - tcg_temp_free_i32(tmp2); - neon_store_reg(rd, pass, tmp); - } - } /* for pass */ - } else if (op < 10) { - /* Shift by immediate and narrow: - VSHRN, VRSHRN, VQSHRN, VQRSHRN. */ - int input_unsigned = (op == 8) ? !u : u; - if (rm & 1) { - return 1; - } - shift = shift - (1 << (size + 3)); - size++; - if (size == 3) { - tmp64 = tcg_const_i64(shift); - neon_load_reg64(cpu_V0, rm); - neon_load_reg64(cpu_V1, rm + 1); - for (pass = 0; pass < 2; pass++) { - TCGv_i64 in; - if (pass == 0) { - in = cpu_V0; - } else { - in = cpu_V1; - } - if (q) { - if (input_unsigned) { - gen_helper_neon_rshl_u64(cpu_V0, in, tmp64); - } else { - gen_helper_neon_rshl_s64(cpu_V0, in, tmp64); - } - } else { - if (input_unsigned) { - gen_ushl_i64(cpu_V0, in, tmp64); - } else { - gen_sshl_i64(cpu_V0, in, tmp64); - } - } - tmp = tcg_temp_new_i32(); - gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0); - neon_store_reg(rd, pass, tmp); - } /* for pass */ - tcg_temp_free_i64(tmp64); - } else { - if (size == 1) { - imm = (uint16_t)shift; - imm |= imm << 16; - } else { - /* size == 2 */ - imm = (uint32_t)shift; - } - tmp2 = tcg_const_i32(imm); - tmp4 = neon_load_reg(rm + 1, 0); - tmp5 = neon_load_reg(rm + 1, 1); - for (pass = 0; pass < 2; pass++) { - if (pass == 0) { - tmp = neon_load_reg(rm, 0); - } else { - tmp = tmp4; - } - gen_neon_shift_narrow(size, tmp, tmp2, q, - input_unsigned); - if (pass == 0) { - tmp3 = neon_load_reg(rm, 1); - } else { - tmp3 = tmp5; - } - gen_neon_shift_narrow(size, tmp3, tmp2, q, - input_unsigned); - tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp3); - tmp = tcg_temp_new_i32(); - gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0); - neon_store_reg(rd, pass, tmp); - } /* for pass */ - tcg_temp_free_i32(tmp2); - } - } else if (op == 10) { - /* VSHLL, VMOVL */ - if (q || (rd & 1)) { - return 1; - } - tmp = neon_load_reg(rm, 0); - tmp2 = neon_load_reg(rm, 1); - for (pass = 0; pass < 2; pass++) { - if (pass == 1) - tmp = tmp2; - - gen_neon_widen(cpu_V0, tmp, size, u); - - if (shift != 0) { - /* The shift is less than the width of the source - type, so we can just shift the whole register. */ - tcg_gen_shli_i64(cpu_V0, cpu_V0, shift); - /* Widen the result of shift: we need to clear - * the potential overflow bits resulting from - * left bits of the narrow input appearing as - * right bits of left the neighbour narrow - * input. */ - if (size < 2 || !u) { - uint64_t imm64; - if (size == 0) { - imm = (0xffu >> (8 - shift)); - imm |= imm << 16; - } else if (size == 1) { - imm = 0xffff >> (16 - shift); - } else { - /* size == 2 */ - imm = 0xffffffff >> (32 - shift); - } - if (size < 2) { - imm64 = imm | (((uint64_t)imm) << 32); - } else { - imm64 = imm; - } - tcg_gen_andi_i64(cpu_V0, cpu_V0, ~imm64); - } - } - neon_store_reg64(cpu_V0, rd + pass); - } - } else if (op >= 14) { - /* VCVT fixed-point. */ - TCGv_ptr fpst; - TCGv_i32 shiftv; - VFPGenFixPointFn *fn; - - if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) { - return 1; - } - - if (!(op & 1)) { - if (u) { - fn = gen_helper_vfp_ultos; - } else { - fn = gen_helper_vfp_sltos; - } - } else { - if (u) { - fn = gen_helper_vfp_touls_round_to_zero; - } else { - fn = gen_helper_vfp_tosls_round_to_zero; - } - } - - /* We have already masked out the must-be-1 top bit of imm6, - * hence this 32-shift where the ARM ARM has 64-imm6. - */ - shift = 32 - shift; - fpst = get_fpstatus_ptr(1); - shiftv = tcg_const_i32(shift); - for (pass = 0; pass < (q ? 4 : 2); pass++) { - TCGv_i32 tmpf = neon_load_reg(rm, pass); - fn(tmpf, tmpf, shiftv, fpst); - neon_store_reg(rd, pass, tmpf); - } - tcg_temp_free_ptr(fpst); - tcg_temp_free_i32(shiftv); - } else { - return 1; - } - } else { /* (insn & 0x00380080) == 0 */ - int invert, reg_ofs, vec_size; - - if (q && (rd & 1)) { - return 1; - } - - op = (insn >> 8) & 0xf; - /* One register and immediate. */ - imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf); - invert = (insn & (1 << 5)) != 0; - /* Note that op = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE. - * We choose to not special-case this and will behave as if a - * valid constant encoding of 0 had been given. - */ - switch (op) { - case 0: case 1: - /* no-op */ - break; - case 2: case 3: - imm <<= 8; - break; - case 4: case 5: - imm <<= 16; - break; - case 6: case 7: - imm <<= 24; - break; - case 8: case 9: - imm |= imm << 16; - break; - case 10: case 11: - imm = (imm << 8) | (imm << 24); - break; - case 12: - imm = (imm << 8) | 0xff; - break; - case 13: - imm = (imm << 16) | 0xffff; - break; - case 14: - imm |= (imm << 8) | (imm << 16) | (imm << 24); - if (invert) { - imm = ~imm; - } - break; - case 15: - if (invert) { - return 1; - } - imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19) - | ((imm & 0x40) ? (0x1f << 25) : (1 << 30)); - break; - } - if (invert) { - imm = ~imm; - } - - reg_ofs = neon_reg_offset(rd, 0); - vec_size = q ? 16 : 8; - - if (op & 1 && op < 12) { - if (invert) { - /* The immediate value has already been inverted, - * so BIC becomes AND. - */ - tcg_gen_gvec_andi(MO_32, reg_ofs, reg_ofs, imm, - vec_size, vec_size); - } else { - tcg_gen_gvec_ori(MO_32, reg_ofs, reg_ofs, imm, - vec_size, vec_size); - } - } else { - /* VMOV, VMVN. */ - if (op == 14 && invert) { - TCGv_i64 t64 = tcg_temp_new_i64(); - - for (pass = 0; pass <= q; ++pass) { - uint64_t val = 0; - int n; - - for (n = 0; n < 8; n++) { - if (imm & (1 << (n + pass * 8))) { - val |= 0xffull << (n * 8); - } - } - tcg_gen_movi_i64(t64, val); - neon_store_reg64(t64, rd + pass); - } - tcg_temp_free_i64(t64); - } else { - tcg_gen_gvec_dup_imm(MO_32, reg_ofs, vec_size, - vec_size, imm); - } - } - } + /* Two registers and shift or reg and imm: handled by decodetree */ + return 1; } else { /* (insn & 0x00800010 == 0x00800000) */ if (size != 3) { op = (insn >> 8) & 0xf; @@ -6350,34 +5866,30 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) if (!dc_isar_feature(aa32_aes, s) || ((rm | rd) & 1)) { return 1; } - ptr1 = vfp_reg_ptr(true, rd); - ptr2 = vfp_reg_ptr(true, rm); - - /* Bit 6 is the lowest opcode bit; it distinguishes between - * encryption (AESE/AESMC) and decryption (AESD/AESIMC) - */ - tmp3 = tcg_const_i32(extract32(insn, 6, 1)); - + /* + * Bit 6 is the lowest opcode bit; it distinguishes + * between encryption (AESE/AESMC) and decryption + * (AESD/AESIMC). + */ if (op == NEON_2RM_AESE) { - gen_helper_crypto_aese(ptr1, ptr2, tmp3); + tcg_gen_gvec_3_ool(vfp_reg_offset(true, rd), + vfp_reg_offset(true, rd), + vfp_reg_offset(true, rm), + 16, 16, extract32(insn, 6, 1), + gen_helper_crypto_aese); } else { - gen_helper_crypto_aesmc(ptr1, ptr2, tmp3); + tcg_gen_gvec_2_ool(vfp_reg_offset(true, rd), + vfp_reg_offset(true, rm), + 16, 16, extract32(insn, 6, 1), + gen_helper_crypto_aesmc); } - tcg_temp_free_ptr(ptr1); - tcg_temp_free_ptr(ptr2); - tcg_temp_free_i32(tmp3); break; case NEON_2RM_SHA1H: if (!dc_isar_feature(aa32_sha1, s) || ((rm | rd) & 1)) { return 1; } - ptr1 = vfp_reg_ptr(true, rd); - ptr2 = vfp_reg_ptr(true, rm); - - gen_helper_crypto_sha1h(ptr1, ptr2); - - tcg_temp_free_ptr(ptr1); - tcg_temp_free_ptr(ptr2); + tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, 16, 16, 0, + gen_helper_crypto_sha1h); break; case NEON_2RM_SHA1SU1: if ((rm | rd) & 1) { @@ -6391,17 +5903,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } else if (!dc_isar_feature(aa32_sha1, s)) { return 1; } - ptr1 = vfp_reg_ptr(true, rd); - ptr2 = vfp_reg_ptr(true, rm); - if (q) { - gen_helper_crypto_sha256su0(ptr1, ptr2); - } else { - gen_helper_crypto_sha1su1(ptr1, ptr2); - } - tcg_temp_free_ptr(ptr1); - tcg_temp_free_ptr(ptr2); + tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, 16, 16, 0, + q ? gen_helper_crypto_sha256su0 + : gen_helper_crypto_sha1su1); break; - case NEON_2RM_VMVN: tcg_gen_gvec_not(0, rd_ofs, rm_ofs, vec_size, vec_size); break; |