From nobody Tue Oct 28 02:16:09 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 1516073808901118.49743659186413; Mon, 15 Jan 2018 19:36:48 -0800 (PST) Received: from localhost ([::1]:59100 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ebI3K-0006PK-Qi for importer@patchew.org; Mon, 15 Jan 2018 22:36:46 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:59579) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ebI16-0004wL-SP for qemu-devel@nongnu.org; Mon, 15 Jan 2018 22:34:31 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ebI14-0003Cq-5G for qemu-devel@nongnu.org; Mon, 15 Jan 2018 22:34:28 -0500 Received: from mail-pg0-x241.google.com ([2607:f8b0:400e:c05::241]:36824) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1ebI13-0003Cf-RV for qemu-devel@nongnu.org; Mon, 15 Jan 2018 22:34:26 -0500 Received: by mail-pg0-x241.google.com with SMTP id k68so1205206pga.3 for ; Mon, 15 Jan 2018 19:34:25 -0800 (PST) Received: from cloudburst.twiddle.net.com (24-181-135-57.dhcp.knwc.wa.charter.com. [24.181.135.57]) by smtp.gmail.com with ESMTPSA id c83sm1281024pfk.8.2018.01.15.19.34.21 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 15 Jan 2018 19:34:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=9grtQqiAm7aUPy8lKE0gV+55M0fH9YJufzZA3xxGJIA=; b=HSIybLV+ys/DGHB5+dviO8kZnOmG0/VPn+Ib/55VDAA43A1YG+f9U9BN4lHn0imGpa eqkS+ayUn4vR70pCvw8Qs+16JHeTfqlYuxXlU2pHjTC4AiU+/LoGEoWdieMggU1FS951 klcqlD1PQI60q7oobDbQlYhbujX7L/8+bGltU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=9grtQqiAm7aUPy8lKE0gV+55M0fH9YJufzZA3xxGJIA=; b=aJ5+On9zu4JT/mb4ZCxfMmq1qEQhvfDHO/4hp+VjIzjVloZ5+sRu6QuD6n0YQemdx1 wBXheUvjHhonkKd5Ij9PvD6v7Ec2qXq5XMUEUrs0ipPMNpvTBMWyQF3IvNuTio9YsZvA /B2zEC/Ig/6vQPWQEQ8z0sV7bkldfXb9UuJXLccmOTFicsR8BlqdHEhlNCfq2Qxh2UHF zPiQO8hwrC3U9Zaf9b62c1fc//vjAp0Z68d5wCiYlg++xed4GNr1peJhwkygTFQp3QU4 5JD36bMRrF+NZdly19fILxjSKzdR2bR80qjLbk+QTIoG54j4aG68c2ft6lPlqCcwUMMC JguA== X-Gm-Message-State: AKwxytfNn9Lxjx1+N9tFcom7TXIAC7GMfTyG5G2M8PyO4zULbJduJ1/6 ED/S6nwtyIf3Aft6abAosZKfrNpJH30= X-Google-Smtp-Source: ACJfBosSHaRzmy7LH7mTW0i+rrxbouwJlqXXb95BpUG1/xpsY7oOpq2A36dgmAmfXbLDAZhWzXTXLg== X-Received: by 10.98.144.79 with SMTP id a76mr13260338pfe.15.1516073664330; Mon, 15 Jan 2018 19:34:24 -0800 (PST) From: Richard Henderson To: qemu-devel@nongnu.org Date: Mon, 15 Jan 2018 19:33:43 -0800 Message-Id: <20180116033404.31532-6-richard.henderson@linaro.org> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180116033404.31532-1-richard.henderson@linaro.org> References: <20180116033404.31532-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::241 Subject: [Qemu-devel] [PATCH v9 05/26] 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: , Cc: peter.maydell@linaro.org 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 | 13 ++ 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 | 297 +++++++++++++++++++++++++++++++++++++++= ++++ tcg/tcg-op-vec.c | 55 ++++++++ tcg/tcg.c | 9 ++ tcg/README | 40 ++++++ 10 files changed, 523 insertions(+) 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 57285ec293..f4afcd258e 100644 --- a/tcg/tcg-op-gvec.h +++ b/tcg/tcg-op-gvec.h @@ -179,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 5560e6439a..bccdaa5eca 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 206ae16b19..18f5da2c8b 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -1293,3 +1293,300 @@ 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); + + 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 { + if (high) { + aofs +=3D oprsz / 2; + bofs +=3D oprsz / 2; + } + tcg_gen_gvec_3_ool(dofs, aofs, bofs, oprsz, maxsz, 0, zip_fns[vece= ]); + return; + } + + 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); + } +} + +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); + + 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 { + tcg_gen_gvec_3_ool(dofs, aofs, bofs, oprsz, maxsz, + (1 << vece) * odd, uzp_fns[vece]); + return; + } + + 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); + } +} + +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