From: Peter Maydell <peter.maydell@linaro.org>
To: Anthony Liguori <aliguori@amazon.com>
Cc: Blue Swirl <blauwirbel@gmail.com>,
qemu-devel@nongnu.org, Aurelien Jarno <aurelien@aurel32.net>
Subject: [Qemu-devel] [PULL 25/38] target-arm: A64: Add SIMD three-different multiply accumulate insns
Date: Wed, 29 Jan 2014 13:39:52 +0000 [thread overview]
Message-ID: <1391002805-26596-26-git-send-email-peter.maydell@linaro.org> (raw)
In-Reply-To: <1391002805-26596-1-git-send-email-peter.maydell@linaro.org>
Add support for the multiply-accumulate instructions from the
SIMD three-different instructions group (C3.6.15):
* skeleton decode of unallocated encodings and split of
the group into its three sub-parts
* framework for handling the 64x64->128 widening subpart
* implementation of the multiply-accumulate instructions
SMLAL, SMLAL2, UMLAL, UMLAL2, SMLSL, SMLSL2, UMLSL, UMLSL2,
UMULL, UMULL2, SMULL, SMULL2
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 233 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 232 insertions(+), 1 deletion(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index c22bbb5..e8479a5 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -700,6 +700,9 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
* zero extend as we are filling a partial chunk of the vector register.
* These functions don't support 128 bit loads/stores, which would be
* normal load/store operations.
+ *
+ * The _i32 versions are useful when operating on 32 bit quantities
+ * (eg for floating point single or using Neon helper functions).
*/
/* Get value of an element within a vector register */
@@ -735,6 +738,32 @@ static void read_vec_element(DisasContext *s, TCGv_i64 tcg_dest, int srcidx,
}
}
+static void read_vec_element_i32(DisasContext *s, TCGv_i32 tcg_dest, int srcidx,
+ int element, TCGMemOp memop)
+{
+ int vect_off = vec_reg_offset(srcidx, element, memop & MO_SIZE);
+ switch (memop) {
+ case MO_8:
+ tcg_gen_ld8u_i32(tcg_dest, cpu_env, vect_off);
+ break;
+ case MO_16:
+ tcg_gen_ld16u_i32(tcg_dest, cpu_env, vect_off);
+ break;
+ case MO_8|MO_SIGN:
+ tcg_gen_ld8s_i32(tcg_dest, cpu_env, vect_off);
+ break;
+ case MO_16|MO_SIGN:
+ tcg_gen_ld16s_i32(tcg_dest, cpu_env, vect_off);
+ break;
+ case MO_32:
+ case MO_32|MO_SIGN:
+ tcg_gen_ld_i32(tcg_dest, cpu_env, vect_off);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
/* Set value of an element within a vector register */
static void write_vec_element(DisasContext *s, TCGv_i64 tcg_src, int destidx,
int element, TCGMemOp memop)
@@ -5518,6 +5547,150 @@ static void disas_simd_shift_imm(DisasContext *s, uint32_t insn)
unsupported_encoding(s, insn);
}
+static void handle_3rd_widening(DisasContext *s, int is_q, int is_u, int size,
+ int opcode, int rd, int rn, int rm)
+{
+ /* 3-reg-different widening insns: 64 x 64 -> 128 */
+ TCGv_i64 tcg_res[2];
+ int pass, accop;
+
+ tcg_res[0] = tcg_temp_new_i64();
+ tcg_res[1] = tcg_temp_new_i64();
+
+ /* Does this op do an adding accumulate, a subtracting accumulate,
+ * or no accumulate at all?
+ */
+ switch (opcode) {
+ case 5:
+ case 8:
+ case 9:
+ accop = 1;
+ break;
+ case 10:
+ case 11:
+ accop = -1;
+ break;
+ default:
+ accop = 0;
+ break;
+ }
+
+ if (accop != 0) {
+ read_vec_element(s, tcg_res[0], rd, 0, MO_64);
+ read_vec_element(s, tcg_res[1], rd, 1, MO_64);
+ }
+
+ /* size == 2 means two 32x32->64 operations; this is worth special
+ * casing because we can generally handle it inline.
+ */
+ if (size == 2) {
+ for (pass = 0; pass < 2; pass++) {
+ TCGv_i64 tcg_op1 = tcg_temp_new_i64();
+ TCGv_i64 tcg_op2 = tcg_temp_new_i64();
+ TCGv_i64 tcg_passres;
+ TCGMemOp memop = MO_32 | (is_u ? 0 : MO_SIGN);
+
+ int elt = pass + is_q * 2;
+
+ read_vec_element(s, tcg_op1, rn, elt, memop);
+ read_vec_element(s, tcg_op2, rm, elt, memop);
+
+ if (accop == 0) {
+ tcg_passres = tcg_res[pass];
+ } else {
+ tcg_passres = tcg_temp_new_i64();
+ }
+
+ switch (opcode) {
+ case 8: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
+ case 10: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
+ case 12: /* UMULL, UMULL2, SMULL, SMULL2 */
+ tcg_gen_mul_i64(tcg_passres, tcg_op1, tcg_op2);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (accop > 0) {
+ tcg_gen_add_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
+ tcg_temp_free_i64(tcg_passres);
+ } else if (accop < 0) {
+ tcg_gen_sub_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
+ tcg_temp_free_i64(tcg_passres);
+ }
+
+ tcg_temp_free_i64(tcg_op1);
+ tcg_temp_free_i64(tcg_op2);
+ }
+ } else {
+ /* size 0 or 1, generally helper functions */
+ for (pass = 0; pass < 2; pass++) {
+ TCGv_i32 tcg_op1 = tcg_temp_new_i32();
+ TCGv_i32 tcg_op2 = tcg_temp_new_i32();
+ TCGv_i64 tcg_passres;
+ int elt = pass + is_q * 2;
+
+ read_vec_element_i32(s, tcg_op1, rn, elt, MO_32);
+ read_vec_element_i32(s, tcg_op2, rm, elt, MO_32);
+
+ if (accop == 0) {
+ tcg_passres = tcg_res[pass];
+ } else {
+ tcg_passres = tcg_temp_new_i64();
+ }
+
+ switch (opcode) {
+ case 8: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
+ case 10: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
+ case 12: /* UMULL, UMULL2, SMULL, SMULL2 */
+ if (size == 0) {
+ if (is_u) {
+ gen_helper_neon_mull_u8(tcg_passres, tcg_op1, tcg_op2);
+ } else {
+ gen_helper_neon_mull_s8(tcg_passres, tcg_op1, tcg_op2);
+ }
+ } else {
+ if (is_u) {
+ gen_helper_neon_mull_u16(tcg_passres, tcg_op1, tcg_op2);
+ } else {
+ gen_helper_neon_mull_s16(tcg_passres, tcg_op1, tcg_op2);
+ }
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ tcg_temp_free_i32(tcg_op1);
+ tcg_temp_free_i32(tcg_op2);
+
+ if (accop > 0) {
+ if (size == 0) {
+ gen_helper_neon_addl_u16(tcg_res[pass], tcg_res[pass],
+ tcg_passres);
+ } else {
+ gen_helper_neon_addl_u32(tcg_res[pass], tcg_res[pass],
+ tcg_passres);
+ }
+ tcg_temp_free_i64(tcg_passres);
+ } else if (accop < 0) {
+ if (size == 0) {
+ gen_helper_neon_subl_u16(tcg_res[pass], tcg_res[pass],
+ tcg_passres);
+ } else {
+ gen_helper_neon_subl_u32(tcg_res[pass], tcg_res[pass],
+ tcg_passres);
+ }
+ tcg_temp_free_i64(tcg_passres);
+ }
+ }
+ }
+
+ write_vec_element(s, tcg_res[0], rd, 0, MO_64);
+ write_vec_element(s, tcg_res[1], rd, 1, MO_64);
+ tcg_temp_free_i64(tcg_res[0]);
+ tcg_temp_free_i64(tcg_res[1]);
+}
+
/* C3.6.15 AdvSIMD three different
* 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0
* +---+---+---+-----------+------+---+------+--------+-----+------+------+
@@ -5526,7 +5699,65 @@ static void disas_simd_shift_imm(DisasContext *s, uint32_t insn)
*/
static void disas_simd_three_reg_diff(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ /* Instructions in this group fall into three basic classes
+ * (in each case with the operation working on each element in
+ * the input vectors):
+ * (1) widening 64 x 64 -> 128 (with possibly Vd as an extra
+ * 128 bit input)
+ * (2) wide 64 x 128 -> 128
+ * (3) narrowing 128 x 128 -> 64
+ * Here we do initial decode, catch unallocated cases and
+ * dispatch to separate functions for each class.
+ */
+ int is_q = extract32(insn, 30, 1);
+ int is_u = extract32(insn, 29, 1);
+ int size = extract32(insn, 22, 2);
+ int opcode = extract32(insn, 12, 4);
+ int rm = extract32(insn, 16, 5);
+ int rn = extract32(insn, 5, 5);
+ int rd = extract32(insn, 0, 5);
+
+ switch (opcode) {
+ case 1: /* SADDW, SADDW2, UADDW, UADDW2 */
+ case 3: /* SSUBW, SSUBW2, USUBW, USUBW2 */
+ /* 64 x 128 -> 128 */
+ unsupported_encoding(s, insn);
+ break;
+ case 4: /* ADDHN, ADDHN2, RADDHN, RADDHN2 */
+ case 6: /* SUBHN, SUBHN2, RSUBHN, RSUBHN2 */
+ /* 128 x 128 -> 64 */
+ unsupported_encoding(s, insn);
+ break;
+ case 9:
+ case 11:
+ case 13:
+ case 14:
+ if (is_u) {
+ unallocated_encoding(s);
+ return;
+ }
+ /* fall through */
+ case 0:
+ case 2:
+ case 5:
+ case 7:
+ unsupported_encoding(s, insn);
+ break;
+ case 8:
+ case 10:
+ case 12:
+ /* 64 x 64 -> 128 */
+ if (size == 3) {
+ unallocated_encoding(s);
+ return;
+ }
+ handle_3rd_widening(s, is_q, is_u, size, opcode, rd, rn, rm);
+ break;
+ default:
+ /* opcode 15 not allocated */
+ unallocated_encoding(s);
+ break;
+ }
}
/* C3.6.16 AdvSIMD three same
--
1.8.5
next prev parent reply other threads:[~2014-01-29 13:40 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-01-29 13:39 [Qemu-devel] [PULL 00/38] target-arm queue Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 01/38] target-arm: A64: Add SIMD ld/st multiple Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 02/38] target-arm: A64: Add SIMD ld/st single Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 03/38] target-arm: A64: Add decode skeleton for SIMD data processing insns Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 04/38] target-arm: A64: Add SIMD EXT Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 05/38] target-arm: A64: Add SIMD TBL/TBLX Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 06/38] target-arm: A64: Add SIMD ZIP/UZP/TRN Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 07/38] target-arm: A64: Add SIMD across-lanes instructions Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 08/38] target-arm: A64: Add SIMD copy operations Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 09/38] target-arm: A64: Add SIMD modified immediate group Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 10/38] target-arm: A64: Add SIMD scalar copy instructions Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 11/38] hw/arm/boot: Don't set up ATAGS for autogenerated dtb booting Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 12/38] ARM: Convert MIDR to a property Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 13/38] ZYNQ: Implement board MIDR control for Zynq Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 14/38] display: avoid multi-statement macro Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 15/38] target-arm: Move arm_rmode_to_sf to a shared location Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 16/38] target-arm: Add AArch32 FP VRINTA, VRINTN, VRINTP and VRINTM Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 17/38] target-arm: Add support for AArch32 FP VRINTR Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 18/38] target-arm: Add support for AArch32 FP VRINTZ Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 19/38] target-arm: Add support for AArch32 FP VRINTX Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 20/38] target-arm: Add support for AArch32 SIMD VRINTX Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 21/38] target-arm: Add set_neon_rmode helper Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 22/38] target-arm: Add AArch32 SIMD VRINTA, VRINTN, VRINTP, VRINTM, VRINTZ Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 23/38] target-arm: Add AArch32 FP VCVTA, VCVTN, VCVTP and VCVTM Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 24/38] target-arm: Add AArch32 SIMD " Peter Maydell
2014-01-29 13:39 ` Peter Maydell [this message]
2014-01-29 13:39 ` [Qemu-devel] [PULL 26/38] target-arm: A64: Add SIMD three-different ABDL instructions Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 27/38] target-arm: A64: Add SIMD scalar 3 same add, sub and compare ops Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 28/38] target-arm: A64: Add top level decode for SIMD 3-same group Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 29/38] target-arm: A64: Add logic ops from SIMD 3 same group Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 30/38] target-arm: A64: Add integer ops from SIMD 3-same group Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 31/38] target-arm: A64: Add simple SIMD 3-same floating point ops Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 32/38] target-arm: A64: Add SIMD shift by immediate Peter Maydell
2014-01-29 13:40 ` [Qemu-devel] [PULL 33/38] linux-headers: Update from Linus' master ba635f8 Peter Maydell
2014-01-29 13:40 ` [Qemu-devel] [PULL 34/38] kvm: Introduce kvm_arch_irqchip_create Peter Maydell
2014-01-29 13:40 ` [Qemu-devel] [PULL 35/38] kvm: Common device control API functions Peter Maydell
2014-01-29 13:40 ` [Qemu-devel] [PULL 36/38] arm: vgic device control api support Peter Maydell
2014-01-29 13:40 ` [Qemu-devel] [PULL 37/38] arm_gic: Introduce define for GIC_NR_SGIS Peter Maydell
2014-01-29 13:40 ` [Qemu-devel] [PULL 38/38] arm_gic: Fix GICD_ICPENDR and GICD_ISPENDR writes Peter Maydell
2014-01-31 14:36 ` [Qemu-devel] [PULL 00/38] target-arm queue Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1391002805-26596-26-git-send-email-peter.maydell@linaro.org \
--to=peter.maydell@linaro.org \
--cc=aliguori@amazon.com \
--cc=aurelien@aurel32.net \
--cc=blauwirbel@gmail.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).