From nobody Tue Oct 28 04:18:24 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1515208574429568.93777362081; Fri, 5 Jan 2018 19:16:14 -0800 (PST) Received: from localhost ([::1]:44036 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eXexx-0000LQ-DP for importer@patchew.org; Fri, 05 Jan 2018 22:16:13 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48241) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eXevr-0007RC-0E for qemu-devel@nongnu.org; Fri, 05 Jan 2018 22:14:06 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eXevn-0004pk-Sc for qemu-devel@nongnu.org; Fri, 05 Jan 2018 22:14:02 -0500 Received: from mail-pg0-x244.google.com ([2607:f8b0:400e:c05::244]:32998) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1eXevn-0004oC-J2 for qemu-devel@nongnu.org; Fri, 05 Jan 2018 22:13:59 -0500 Received: by mail-pg0-x244.google.com with SMTP id i196so2716433pgd.0 for ; Fri, 05 Jan 2018 19:13:59 -0800 (PST) Received: from cloudburst.twiddle.net (97-113-183-164.tukw.qwest.net. [97.113.183.164]) by smtp.gmail.com with ESMTPSA id g10sm17740595pfe.77.2018.01.05.19.13.56 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 05 Jan 2018 19:13:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id:in-reply-to:references; bh=Qr/mdYIXzaibD/aGf+TjVpNhfFLYB42cPYlYCbDvgnI=; b=agnM00sIp9JlvAYZni3tOZnlrxaZHWgeFOJvk8QctmxFooRzP2NYPx3P4Swq7kcN3h MHYlTCVjotrjqzSTKPz/M3hAy1uBZ6h8YZLHZ0M/6eOR1t3uRfnTtR08U1saC7w18a94 vuYDYmqD5M/RitnTE7OymrrG+LUGJEhm6YEI4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=Qr/mdYIXzaibD/aGf+TjVpNhfFLYB42cPYlYCbDvgnI=; b=OuXt+DI67fhPADCgGc9/wqECHlVy1+gXUBzpEITW8zgXvA7nnNMIgY9R8yFOx0ydBa ICzYZS3GWQge3x8Ddm4TGRA220fCZ8kfDDKvIwMb3wnxlf4ueVVEq3AiFRKAcg8/77Nq jfe4J2ykn8nRrJXWpLcMz15i1M/f6aRJlSinc9O6FLvL2xeRm6V4DcBNTdKY74oDmO6R 5tu+aPtv/smTgan0Nr8BLwKScDZV9faeQb+cQP6x1f9iSbYlz8+7ENPuwwA7MbR4FuXX NcrcbHNP3N7ZjTaYOB5gQBkfZlxu8MgJgdhofQq8BFIRFT4yaaVS5JF9DzHdZ1jwnNbf 9aIg== X-Gm-Message-State: AKGB3mILUZkvJ6bLXuNinDshLEKn8XHfnqjc/ifd3pa3wdrJVE7yAgy2 G4afPcR+qjTzU4nvNMmuGxAFQ02FO4E= X-Google-Smtp-Source: ACJfBoujIIV6zHlL2kUwKgd1GygkVliFO2Y4UutEbA0jQDRWtLaQ1aMn5hNuGZawxC5J0FctKm52ig== X-Received: by 10.98.210.133 with SMTP id c127mr4735823pfg.160.1515208437979; Fri, 05 Jan 2018 19:13:57 -0800 (PST) From: Richard Henderson To: qemu-devel@nongnu.org Date: Fri, 5 Jan 2018 19:13:28 -0800 Message-Id: <20180106031346.6650-6-richard.henderson@linaro.org> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180106031346.6650-1-richard.henderson@linaro.org> References: <20180106031346.6650-1-richard.henderson@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:400e:c05::244 Subject: [Qemu-devel] [PATCH v8 05/23] tcg: Add generic vector ops for interleave X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Includes zip, unzip, and transform. Signed-off-by: Richard Henderson --- accel/tcg/tcg-runtime.h | 15 ++ tcg/tcg-op-gvec.h | 17 +++ tcg/tcg-op.h | 6 + tcg/tcg-opc.h | 7 + tcg/tcg.h | 3 + accel/tcg/tcg-runtime-gvec.c | 78 +++++++++++ tcg/tcg-op-gvec.c | 317 +++++++++++++++++++++++++++++++++++++++= +++- tcg/tcg-op-vec.c | 55 ++++++++ tcg/tcg.c | 9 ++ tcg/README | 40 ++++++ 10 files changed, 545 insertions(+), 2 deletions(-) diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h index 76ee41ce58..c6de749134 100644 --- a/accel/tcg/tcg-runtime.h +++ b/accel/tcg/tcg-runtime.h @@ -163,3 +163,18 @@ DEF_HELPER_FLAGS_4(gvec_or, TCG_CALL_NO_RWG, void, ptr= , ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_xor, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_andc, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_orc, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_zip8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_zip16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_zip32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_zip64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_uzp8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uzp16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uzp32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uzp64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_trn8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_trn16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_trn32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_trn64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/tcg/tcg-op-gvec.h b/tcg/tcg-op-gvec.h index 9d795fbb30..1d97e80e18 100644 --- a/tcg/tcg-op-gvec.h +++ b/tcg/tcg-op-gvec.h @@ -87,6 +87,8 @@ typedef struct { gen_helper_gvec_2 *fno; /* The opcode, if any, to which this corresponds. */ TCGOpcode opc; + /* The data argument to the out-of-line helper. */ + uint32_t data; /* The vector element size, if applicable. */ uint8_t vece; /* Prefer i64 to v64. */ @@ -104,6 +106,8 @@ typedef struct { gen_helper_gvec_3 *fno; /* The opcode, if any, to which this corresponds. */ TCGOpcode opc; + /* The data argument to the out-of-line helper. */ + uint32_t data; /* The vector element size, if applicable. */ uint8_t vece; /* Prefer i64 to v64. */ @@ -175,6 +179,19 @@ void tcg_gen_gvec_dup16i(uint32_t dofs, uint32_t s, ui= nt32_t m, uint16_t x); void tcg_gen_gvec_dup32i(uint32_t dofs, uint32_t s, uint32_t m, uint32_t x= ); void tcg_gen_gvec_dup64i(uint32_t dofs, uint32_t s, uint32_t m, uint64_t x= ); =20 +void tcg_gen_gvec_zipl(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz); +void tcg_gen_gvec_ziph(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz); +void tcg_gen_gvec_uzpe(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz); +void tcg_gen_gvec_uzpo(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz); +void tcg_gen_gvec_trne(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz); +void tcg_gen_gvec_trno(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz); + /* * 64-bit vector operations. Use these when the register has been allocat= ed * with tcg_global_mem_new_i64, and so we cannot also address it via point= er. diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 09fec5693f..87be11a90d 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -927,6 +927,12 @@ void tcg_gen_andc_vec(unsigned vece, TCGv_vec r, TCGv_= vec a, TCGv_vec b); void tcg_gen_orc_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b); void tcg_gen_not_vec(unsigned vece, TCGv_vec r, TCGv_vec a); void tcg_gen_neg_vec(unsigned vece, TCGv_vec r, TCGv_vec a); +void tcg_gen_zipl_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b); +void tcg_gen_ziph_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b); +void tcg_gen_uzpe_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b); +void tcg_gen_uzpo_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b); +void tcg_gen_trne_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b); +void tcg_gen_trno_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b); =20 void tcg_gen_ld_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset); void tcg_gen_st_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset); diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h index b4e16cfbc3..c911d62442 100644 --- a/tcg/tcg-opc.h +++ b/tcg/tcg-opc.h @@ -229,6 +229,13 @@ DEF(andc_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_a= ndc_vec)) DEF(orc_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_orc_vec)) DEF(not_vec, 1, 1, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_not_vec)) =20 +DEF(zipl_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_zip_vec)) +DEF(ziph_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_zip_vec)) +DEF(uzpe_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_uzp_vec)) +DEF(uzpo_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_uzp_vec)) +DEF(trne_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_trn_vec)) +DEF(trno_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_trn_vec)) + DEF(last_generic, 0, 0, 0, TCG_OPF_NOT_PRESENT) =20 #if TCG_TARGET_MAYBE_vec diff --git a/tcg/tcg.h b/tcg/tcg.h index 0e9d79bdd4..d0678ac769 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -178,6 +178,9 @@ typedef uint64_t TCGRegSet; #define TCG_TARGET_HAS_not_vec 0 #define TCG_TARGET_HAS_andc_vec 0 #define TCG_TARGET_HAS_orc_vec 0 +#define TCG_TARGET_HAS_zip_vec 0 +#define TCG_TARGET_HAS_uzp_vec 0 +#define TCG_TARGET_HAS_trn_vec 0 #else #define TCG_TARGET_MAYBE_vec 1 #endif diff --git a/accel/tcg/tcg-runtime-gvec.c b/accel/tcg/tcg-runtime-gvec.c index cd1ce12b7e..628df811b2 100644 --- a/accel/tcg/tcg-runtime-gvec.c +++ b/accel/tcg/tcg-runtime-gvec.c @@ -293,3 +293,81 @@ void HELPER(gvec_orc)(void *d, void *a, void *b, uint3= 2_t desc) } clear_high(d, oprsz, desc); } + +/* The size of the alloca in the following is currently bounded to 2k. */ + +#define DO_ZIP(NAME, TYPE) \ +void HELPER(NAME)(void *d, void *a, void *b, uint32_t desc) = \ +{ = \ + intptr_t oprsz =3D simd_oprsz(desc); = \ + intptr_t oprsz_2 =3D oprsz / 2; = \ + intptr_t i; = \ + /* We produce output faster than we consume input. = \ + Therefore we must be mindful of possible overlap. */ = \ + if (unlikely((a - d) < (uintptr_t)oprsz)) { = \ + void *a_new =3D alloca(oprsz_2); = \ + memcpy(a_new, a, oprsz_2); = \ + a =3D a_new; = \ + } = \ + if (unlikely((b - d) < (uintptr_t)oprsz)) { = \ + void *b_new =3D alloca(oprsz_2); = \ + memcpy(b_new, b, oprsz_2); = \ + b =3D b_new; = \ + } = \ + for (i =3D 0; i < oprsz_2; i +=3D sizeof(TYPE)) { = \ + *(TYPE *)(d + 2 * i + 0) =3D *(TYPE *)(a + i); \ + *(TYPE *)(d + 2 * i + sizeof(TYPE)) =3D *(TYPE *)(b + i); \ + } = \ + clear_high(d, oprsz, desc); = \ +} + +DO_ZIP(gvec_zip8, uint8_t) +DO_ZIP(gvec_zip16, uint16_t) +DO_ZIP(gvec_zip32, uint32_t) +DO_ZIP(gvec_zip64, uint64_t) + +#define DO_UZP(NAME, TYPE) \ +void HELPER(NAME)(void *d, void *a, void *b, uint32_t desc) = \ +{ = \ + intptr_t oprsz =3D simd_oprsz(desc); = \ + intptr_t oprsz_2 =3D oprsz / 2; = \ + intptr_t odd_ofs =3D simd_data(desc); = \ + intptr_t i; = \ + if (unlikely((b - d) < (uintptr_t)oprsz)) { = \ + void *b_new =3D alloca(oprsz); = \ + memcpy(b_new, b, oprsz); = \ + b =3D b_new; = \ + } = \ + for (i =3D 0; i < oprsz_2; i +=3D sizeof(TYPE)) { = \ + *(TYPE *)(d + i) =3D *(TYPE *)(a + 2 * i + odd_ofs); = \ + } = \ + for (i =3D 0; i < oprsz_2; i +=3D sizeof(TYPE)) { = \ + *(TYPE *)(d + oprsz_2 + i) =3D *(TYPE *)(b + 2 * i + odd_ofs); = \ + } = \ + clear_high(d, oprsz, desc); = \ +} + +DO_UZP(gvec_uzp8, uint8_t) +DO_UZP(gvec_uzp16, uint16_t) +DO_UZP(gvec_uzp32, uint32_t) +DO_UZP(gvec_uzp64, uint64_t) + +#define DO_TRN(NAME, TYPE) \ +void HELPER(NAME)(void *d, void *a, void *b, uint32_t desc) = \ +{ = \ + intptr_t oprsz =3D simd_oprsz(desc); = \ + intptr_t odd_ofs =3D simd_data(desc); = \ + intptr_t i; = \ + for (i =3D 0; i < oprsz; i +=3D 2 * sizeof(TYPE)) { = \ + TYPE ae =3D *(TYPE *)(a + i + odd_ofs); = \ + TYPE be =3D *(TYPE *)(b + i + odd_ofs); = \ + *(TYPE *)(d + i + 0) =3D ae; \ + *(TYPE *)(d + i + sizeof(TYPE)) =3D be; \ + } = \ + clear_high(d, oprsz, desc); = \ +} + +DO_TRN(gvec_trn8, uint8_t) +DO_TRN(gvec_trn16, uint16_t) +DO_TRN(gvec_trn32, uint32_t) +DO_TRN(gvec_trn64, uint64_t) diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index 2b7f4c8544..c4ecef0e1e 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -780,7 +780,7 @@ void tcg_gen_gvec_2(uint32_t dofs, uint32_t aofs, } =20 do_ool: - tcg_gen_gvec_2_ool(dofs, aofs, oprsz, maxsz, 0, g->fno); + tcg_gen_gvec_2_ool(dofs, aofs, oprsz, maxsz, g->data, g->fno); } =20 /* Expand a vector three-operand operation. */ @@ -864,7 +864,7 @@ void tcg_gen_gvec_3(uint32_t dofs, uint32_t aofs, uint3= 2_t bofs, } =20 do_ool: - tcg_gen_gvec_3_ool(dofs, aofs, bofs, oprsz, maxsz, 0, g->fno); + tcg_gen_gvec_3_ool(dofs, aofs, bofs, oprsz, maxsz, g->data, g->fno); } =20 /* Expand a vector four-operand operation. */ @@ -1401,3 +1401,316 @@ void tcg_gen_gvec_orc(unsigned vece, uint32_t dofs,= uint32_t aofs, }; tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &g); } + +static void do_zip(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz, + bool high) +{ + static gen_helper_gvec_3 * const zip_fns[4] =3D { + gen_helper_gvec_zip8, + gen_helper_gvec_zip16, + gen_helper_gvec_zip32, + gen_helper_gvec_zip64, + }; + + TCGType type; + uint32_t step, i, n; + TCGOpcode zip_op; + + check_size_align(oprsz, maxsz, dofs | aofs | bofs); + check_overlap_3(dofs, aofs, bofs, oprsz); + tcg_debug_assert(vece <=3D MO_64); + + /* Quick check for sizes we won't support inline. */ + if (oprsz > 4 * 32 || maxsz > MAX_UNROLL * 32) { + goto do_ool; + } + + zip_op =3D high ? INDEX_op_ziph_vec : INDEX_op_zipl_vec; + + /* Since these operations don't operate in lock-step lanes, + we must care for overlap. */ + if (TCG_TARGET_HAS_v256 && oprsz % 32 =3D=3D 0 && oprsz / 32 <=3D 8 + && tcg_can_emit_vec_op(zip_op, TCG_TYPE_V256, vece)) { + type =3D TCG_TYPE_V256; + step =3D 32; + n =3D oprsz / 32; + } else if (TCG_TARGET_HAS_v128 && oprsz % 16 =3D=3D 0 && oprsz / 16 <= =3D 8 + && tcg_can_emit_vec_op(zip_op, TCG_TYPE_V128, vece)) { + type =3D TCG_TYPE_V128; + step =3D 16; + n =3D oprsz / 16; + } else if (TCG_TARGET_HAS_v64 && oprsz % 8 =3D=3D 0 && oprsz / 8 <=3D 8 + && tcg_can_emit_vec_op(zip_op, TCG_TYPE_V64, vece)) { + type =3D TCG_TYPE_V64; + step =3D 8; + n =3D oprsz / 8; + } else { + goto do_ool; + } + + if (n =3D=3D 1) { + TCGv_vec t1 =3D tcg_temp_new_vec(type); + TCGv_vec t2 =3D tcg_temp_new_vec(type); + + tcg_gen_ld_vec(t1, cpu_env, aofs); + tcg_gen_ld_vec(t2, cpu_env, bofs); + if (high) { + tcg_gen_ziph_vec(vece, t1, t1, t2); + } else { + tcg_gen_zipl_vec(vece, t1, t1, t2); + } + tcg_gen_st_vec(t1, cpu_env, dofs); + tcg_temp_free_vec(t1); + tcg_temp_free_vec(t2); + } else { + TCGv_vec ta[4], tb[4], tmp; + + if (high) { + aofs +=3D oprsz / 2; + bofs +=3D oprsz / 2; + } + + for (i =3D 0; i < (n / 2 + n % 2); ++i) { + ta[i] =3D tcg_temp_new_vec(type); + tb[i] =3D tcg_temp_new_vec(type); + tcg_gen_ld_vec(ta[i], cpu_env, aofs + i * step); + tcg_gen_ld_vec(tb[i], cpu_env, bofs + i * step); + } + + tmp =3D tcg_temp_new_vec(type); + for (i =3D 0; i < n; ++i) { + if (i & 1) { + tcg_gen_ziph_vec(vece, tmp, ta[i / 2], tb[i / 2]); + } else { + tcg_gen_zipl_vec(vece, tmp, ta[i / 2], tb[i / 2]); + } + tcg_gen_st_vec(tmp, cpu_env, dofs + i * step); + } + tcg_temp_free_vec(tmp); + + for (i =3D 0; i < (n / 2 + n % 2); ++i) { + tcg_temp_free_vec(ta[i]); + tcg_temp_free_vec(tb[i]); + } + } + if (oprsz < maxsz) { + expand_clr(dofs + oprsz, maxsz - oprsz); + } + return; + + do_ool: + if (high) { + aofs +=3D oprsz / 2; + bofs +=3D oprsz / 2; + } + tcg_gen_gvec_3_ool(dofs, aofs, bofs, oprsz, maxsz, 0, zip_fns[vece]); +} + +void tcg_gen_gvec_zipl(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz) +{ + do_zip(vece, dofs, aofs, bofs, oprsz, maxsz, false); +} + +void tcg_gen_gvec_ziph(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz) +{ + do_zip(vece, dofs, aofs, bofs, oprsz, maxsz, true); +} + +static void do_uzp(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz, bool odd) +{ + static gen_helper_gvec_3 * const uzp_fns[4] =3D { + gen_helper_gvec_uzp8, + gen_helper_gvec_uzp16, + gen_helper_gvec_uzp32, + gen_helper_gvec_uzp64, + }; + + TCGType type; + uint32_t step, i, n; + TCGv_vec t[8]; + TCGOpcode uzp_op; + + check_size_align(oprsz, maxsz, dofs | aofs | bofs); + check_overlap_3(dofs, aofs, bofs, oprsz); + tcg_debug_assert(vece <=3D MO_64); + + /* Quick check for sizes we won't support inline. */ + if (oprsz > 4 * 32 || maxsz > MAX_UNROLL * 32) { + goto do_ool; + } + + uzp_op =3D odd ? INDEX_op_uzpo_vec : INDEX_op_uzpe_vec; + + /* Since these operations don't operate in lock-step lanes, + we must care for overlap. */ + if (TCG_TARGET_HAS_v256 && oprsz % 32 =3D=3D 0 && oprsz / 32 <=3D 4 + && tcg_can_emit_vec_op(uzp_op, TCG_TYPE_V256, vece)) { + type =3D TCG_TYPE_V256; + step =3D 32; + n =3D oprsz / 32; + } else if (TCG_TARGET_HAS_v128 && oprsz % 16 =3D=3D 0 && oprsz / 16 <= =3D 4 + && tcg_can_emit_vec_op(uzp_op, TCG_TYPE_V128, vece)) { + type =3D TCG_TYPE_V128; + step =3D 16; + n =3D oprsz / 16; + } else if (TCG_TARGET_HAS_v64 && oprsz % 8 =3D=3D 0 && oprsz / 8 <=3D 4 + && tcg_can_emit_vec_op(uzp_op, TCG_TYPE_V64, vece)) { + type =3D TCG_TYPE_V64; + step =3D 8; + n =3D oprsz / 8; + } else { + goto do_ool; + } + + for (i =3D 0; i < n; ++i) { + t[i] =3D tcg_temp_new_vec(type); + tcg_gen_ld_vec(t[i], cpu_env, aofs + i * step); + } + for (i =3D 0; i < n; ++i) { + t[n + i] =3D tcg_temp_new_vec(type); + tcg_gen_ld_vec(t[n + i], cpu_env, bofs + i * step); + } + for (i =3D 0; i < n; ++i) { + if (odd) { + tcg_gen_uzpo_vec(vece, t[2 * i], t[2 * i], t[2 * i + 1]); + } else { + tcg_gen_uzpe_vec(vece, t[2 * i], t[2 * i], t[2 * i + 1]); + } + tcg_gen_st_vec(t[2 * i], cpu_env, dofs + i * step); + tcg_temp_free_vec(t[2 * i]); + tcg_temp_free_vec(t[2 * i + 1]); + } + if (oprsz < maxsz) { + expand_clr(dofs + oprsz, maxsz - oprsz); + } + return; + + do_ool: + tcg_gen_gvec_3_ool(dofs, aofs, bofs, oprsz, maxsz, + (1 << vece) * odd, uzp_fns[vece]); +} + +void tcg_gen_gvec_uzpe(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz) +{ + do_uzp(vece, dofs, aofs, bofs, oprsz, maxsz, false); +} + +void tcg_gen_gvec_uzpo(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz) +{ + do_uzp(vece, dofs, aofs, bofs, oprsz, maxsz, true); +} + +static void gen_trne8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) +{ + uint64_t m =3D 0x00ff00ff00ff00ffull; + tcg_gen_andi_i64(a, a, m); + tcg_gen_andi_i64(b, b, m); + tcg_gen_shli_i64(b, b, 8); + tcg_gen_or_i64(d, a, b); +} + +static void gen_trne16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) +{ + uint64_t m =3D 0x0000ffff0000ffffull; + tcg_gen_andi_i64(a, a, m); + tcg_gen_andi_i64(b, b, m); + tcg_gen_shli_i64(b, b, 16); + tcg_gen_or_i64(d, a, b); +} + +static void gen_trne32_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) +{ + tcg_gen_deposit_i64(d, a, b, 32, 32); +} + +void tcg_gen_gvec_trne(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz) +{ + static const GVecGen3 g[4] =3D { + { .fni8 =3D gen_trne8_i64, + .fniv =3D tcg_gen_trne_vec, + .fno =3D gen_helper_gvec_trn8, + .opc =3D INDEX_op_trne_vec, + .vece =3D MO_8 }, + { .fni8 =3D gen_trne16_i64, + .fniv =3D tcg_gen_trne_vec, + .fno =3D gen_helper_gvec_trn16, + .opc =3D INDEX_op_trne_vec, + .vece =3D MO_16 }, + { .fni8 =3D gen_trne32_i64, + .fniv =3D tcg_gen_trne_vec, + .fno =3D gen_helper_gvec_trn32, + .opc =3D INDEX_op_trne_vec, + .vece =3D MO_32 }, + { .fniv =3D tcg_gen_trne_vec, + .fno =3D gen_helper_gvec_trn64, + .opc =3D INDEX_op_trne_vec, + .vece =3D MO_64 }, + }; + + tcg_debug_assert(vece <=3D MO_64); + tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &g[vece]); +} + +static void gen_trno8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) +{ + uint64_t m =3D 0xff00ff00ff00ff00ull; + tcg_gen_andi_i64(a, a, m); + tcg_gen_andi_i64(b, b, m); + tcg_gen_shri_i64(a, a, 8); + tcg_gen_or_i64(d, a, b); +} + +static void gen_trno16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) +{ + uint64_t m =3D 0xffff0000ffff0000ull; + tcg_gen_andi_i64(a, a, m); + tcg_gen_andi_i64(b, b, m); + tcg_gen_shri_i64(a, a, 16); + tcg_gen_or_i64(d, a, b); +} + +static void gen_trno32_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) +{ + tcg_gen_shri_i64(a, a, 32); + tcg_gen_deposit_i64(d, b, a, 0, 32); +} + +void tcg_gen_gvec_trno(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz) +{ + static const GVecGen3 g[4] =3D { + { .fni8 =3D gen_trno8_i64, + .fniv =3D tcg_gen_trno_vec, + .fno =3D gen_helper_gvec_trn8, + .opc =3D INDEX_op_trno_vec, + .data =3D 1, + .vece =3D MO_8 }, + { .fni8 =3D gen_trno16_i64, + .fniv =3D tcg_gen_trno_vec, + .fno =3D gen_helper_gvec_trn16, + .opc =3D INDEX_op_trno_vec, + .data =3D 2, + .vece =3D MO_16 }, + { .fni8 =3D gen_trno32_i64, + .fniv =3D tcg_gen_trno_vec, + .fno =3D gen_helper_gvec_trn32, + .opc =3D INDEX_op_trno_vec, + .data =3D 4, + .vece =3D MO_32 }, + { .fniv =3D tcg_gen_trno_vec, + .fno =3D gen_helper_gvec_trn64, + .opc =3D INDEX_op_trno_vec, + .data =3D 8, + .vece =3D MO_64 }, + }; + + tcg_debug_assert(vece <=3D MO_64); + tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &g[vece]); +} diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c index 5cfe4af6bd..a5d0ff89c3 100644 --- a/tcg/tcg-op-vec.c +++ b/tcg/tcg-op-vec.c @@ -380,3 +380,58 @@ void tcg_gen_neg_vec(unsigned vece, TCGv_vec r, TCGv_v= ec a) tcg_temp_free_vec(t); } } + +static void do_interleave(TCGOpcode opc, unsigned vece, + TCGv_vec r, TCGv_vec a, TCGv_vec b) +{ + TCGTemp *rt =3D tcgv_vec_temp(r); + TCGTemp *at =3D tcgv_vec_temp(a); + TCGTemp *bt =3D tcgv_vec_temp(b); + TCGArg ri =3D temp_arg(rt); + TCGArg ai =3D temp_arg(at); + TCGArg bi =3D temp_arg(bt); + TCGType type =3D rt->base_type; + unsigned vecl =3D type - TCG_TYPE_V64; + int can; + + tcg_debug_assert(at->base_type =3D=3D type); + tcg_debug_assert(bt->base_type =3D=3D type); + tcg_debug_assert((8 << vece) <=3D (32 << vecl)); + can =3D tcg_can_emit_vec_op(opc, type, vece); + if (can > 0) { + vec_gen_3(opc, type, vece, ri, ai, bi); + } else { + tcg_debug_assert(can < 0); + tcg_expand_vec_op(opc, type, vece, ri, ai, bi); + } +} + +void tcg_gen_zipl_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) +{ + do_interleave(INDEX_op_zipl_vec, vece, r, a, b); +} + +void tcg_gen_ziph_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) +{ + do_interleave(INDEX_op_ziph_vec, vece, r, a, b); +} + +void tcg_gen_uzpe_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) +{ + do_interleave(INDEX_op_uzpe_vec, vece, r, a, b); +} + +void tcg_gen_uzpo_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) +{ + do_interleave(INDEX_op_uzpo_vec, vece, r, a, b); +} + +void tcg_gen_trne_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) +{ + do_interleave(INDEX_op_trne_vec, vece, r, a, b); +} + +void tcg_gen_trno_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) +{ + do_interleave(INDEX_op_trno_vec, vece, r, a, b); +} diff --git a/tcg/tcg.c b/tcg/tcg.c index b4f8938fb0..33e3c03cbc 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1403,6 +1403,15 @@ bool tcg_op_supported(TCGOpcode op) return have_vec && TCG_TARGET_HAS_andc_vec; case INDEX_op_orc_vec: return have_vec && TCG_TARGET_HAS_orc_vec; + case INDEX_op_zipl_vec: + case INDEX_op_ziph_vec: + return have_vec && TCG_TARGET_HAS_zip_vec; + case INDEX_op_uzpe_vec: + case INDEX_op_uzpo_vec: + return have_vec && TCG_TARGET_HAS_uzp_vec; + case INDEX_op_trne_vec: + case INDEX_op_trno_vec: + return have_vec && TCG_TARGET_HAS_trn_vec; =20 default: tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS); diff --git a/tcg/README b/tcg/README index e14990fb9b..8ab8d3ab7e 100644 --- a/tcg/README +++ b/tcg/README @@ -561,6 +561,46 @@ E.g. VECL=3D1 -> 64 << 1 -> v128, and VECE=3D2 -> 1 <<= 2 -> i32. Similarly, logical operations with and without compliment. Note that VECE is unused. =20 +* zipl_vec v0, v1, v2 +* ziph_vec v0, v1, v2 + + "Zip" two vectors together, either the low half of v1/v2 or the high hal= f. + The name comes from ARM ARM; the equivalent function in Intel terminology + is the less scrutable "punpck". The effect is + + part =3D ("high" ? VECL/VECE/2 : 0); + for (i =3D 0; i < VECL/VECE/2; ++i) { + v0[2i + 0] =3D v1[i + part]; + v0[2i + 1] =3D v2[i + part]; + } + +* uzpe_vec v0, v1, v2 +* uzpo_vec v0, v1, v2 + + "Unzip" two vectors, either the even elements or the odd elements. + If v1 and v2 are the result of zipl and ziph, this performs the + inverse operation. The effect is + + part =3D ("odd" ? 1 : 0) + for (i =3D 0; i < VECL/VECE/2; ++i) { + v0[i] =3D v1[2i + part]; + } + for (i =3D 0; i < VECL/VECE/2; ++i) { + v0[i + VECL/VECE/2] =3D v1[2i + part]; + } + +* trne_vec v0, v1, v2 +* trno_vec v1, v1, v2 + + "Transpose" two vectors, either the even elements or the odd elements. + The effect is + + part =3D ("odd" ? 1 : 0) + for (i =3D 0; i < VECL/VECE/2; ++i) { + v0[2i + 0] =3D v1[2i + part]; + v0[2i + 1] =3D v2[2i + part]; + } + ********* =20 Note 1: Some shortcuts are defined when the last operand is known to be --=20 2.14.3