[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 27/37] target/i386: Use tcg gvec ops for pmovmskb
From: |
Paolo Bonzini |
Subject: |
[PATCH v2 27/37] target/i386: Use tcg gvec ops for pmovmskb |
Date: |
Tue, 20 Sep 2022 19:24:57 +0200 |
From: Richard Henderson <richard.henderson@linaro.org>
As pmovmskb is used by strlen et al, this is the third
highest overhead sse operation at %0.8.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
[Reorganize to generate code for any vector size. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
target/i386/tcg/emit.c.inc | 90 +++++++++++++++++++++++++++++++++++---
1 file changed, 85 insertions(+), 5 deletions(-)
diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc
index c5e90111a9..5345e791b7 100644
--- a/target/i386/tcg/emit.c.inc
+++ b/target/i386/tcg/emit.c.inc
@@ -1192,14 +1192,94 @@ static void gen_PINSR(DisasContext *s, CPUX86State
*env, X86DecodedInsn *decode)
gen_pinsr(s, env, decode, decode->op[2].ot);
}
+static void gen_pmovmskb_i64(TCGv_i64 d, TCGv_i64 s)
+{
+ TCGv_i64 t = tcg_temp_new_i64();
+
+ tcg_gen_andi_i64(d, s, 0x8080808080808080ull);
+
+ /*
+ * After each shift+or pair:
+ * 0: a.......b.......c.......d.......e.......f.......g.......h.......
+ * 7: ab......bc......cd......de......ef......fg......gh......h.......
+ * 14: abcd....bcde....cdef....defg....efgh....fgh.....gh......h.......
+ * 28: abcdefghbcdefgh.cdefgh..defgh...efgh....fgh.....gh......h.......
+ * The result is left in the high bits of the word.
+ */
+ tcg_gen_shli_i64(t, d, 7);
+ tcg_gen_or_i64(d, d, t);
+ tcg_gen_shli_i64(t, d, 14);
+ tcg_gen_or_i64(d, d, t);
+ tcg_gen_shli_i64(t, d, 28);
+ tcg_gen_or_i64(d, d, t);
+}
+
+static void gen_pmovmskb_vec(unsigned vece, TCGv_vec d, TCGv_vec s)
+{
+ TCGv_vec t = tcg_temp_new_vec_matching(d);
+ TCGv_vec m = tcg_constant_vec_matching(d, MO_8, 0x80);
+
+ /* See above */
+ tcg_gen_and_vec(vece, d, s, m);
+ tcg_gen_shli_vec(vece, t, d, 7);
+ tcg_gen_or_vec(vece, d, d, t);
+ tcg_gen_shli_vec(vece, t, d, 14);
+ tcg_gen_or_vec(vece, d, d, t);
+ if (vece == MO_64) {
+ tcg_gen_shli_vec(vece, t, d, 28);
+ tcg_gen_or_vec(vece, d, d, t);
+ }
+}
+
+#ifdef TARGET_I386
+#define TCG_TARGET_HAS_extract2_tl TCG_TARGET_HAS_extract2_i32
+#else
+#define TCG_TARGET_HAS_extract2_tl TCG_TARGET_HAS_extract2_i64
+#endif
+
static void gen_PMOVMSKB(DisasContext *s, CPUX86State *env, X86DecodedInsn
*decode)
{
- if (s->prefix & PREFIX_DATA) {
- gen_helper_pmovmskb_xmm(s->tmp2_i32, cpu_env, OP_PTR2);
- } else {
- gen_helper_pmovmskb_mmx(s->tmp2_i32, cpu_env, OP_PTR2);
+ static const TCGOpcode vecop_list[] = { INDEX_op_shli_vec, 0 };
+ static const GVecGen2 g = {
+ .fni8 = gen_pmovmskb_i64,
+ .fniv = gen_pmovmskb_vec,
+ .opt_opc = vecop_list,
+ .vece = MO_64,
+ .prefer_i64 = TCG_TARGET_REG_BITS == 64
+ };
+ MemOp ot = decode->op[2].ot;
+ int vec_len = vector_len(s, decode);
+ TCGv t = tcg_temp_new();
+
+ tcg_gen_gvec_2(offsetof(CPUX86State, xmm_t0) + xmm_offset(ot),
decode->op[2].offset,
+ vec_len, vec_len, &g);
+ tcg_gen_ld8u_tl(s->T0, cpu_env, offsetof(CPUX86State, xmm_t0.ZMM_B(vec_len
- 1)));
+ while (vec_len > 8) {
+ vec_len -= 8;
+ if (TCG_TARGET_HAS_extract2_tl) {
+ /*
+ * Load the next byte of the result into the high byte of T.
+ * TCG does a similar expansion of deposit to shl+extract2; by
+ * loading the whole word, the shift left is avoided.
+ */
+#ifdef TARGET_X86_64
+ tcg_gen_ld_tl(t, cpu_env, offsetof(CPUX86State,
xmm_t0.ZMM_Q((vec_len - 1) / 8)));
+#else
+ tcg_gen_ld_tl(t, cpu_env, offsetof(CPUX86State,
xmm_t0.ZMM_L((vec_len - 1) / 4)));
+#endif
+
+ tcg_gen_extract2_tl(s->T0, t, s->T0, TARGET_LONG_BITS - 8);
+ } else {
+ /*
+ * The _previous_ value is deposited into bits 8 and higher of t.
Because
+ * those bits are known to be zero after ld8u, this becomes a
shift+or
+ * if deposit is not available.
+ */
+ tcg_gen_ld8u_tl(t, cpu_env, offsetof(CPUX86State,
xmm_t0.ZMM_B(vec_len - 1)));
+ tcg_gen_deposit_tl(s->T0, t, s->T0, 8, TARGET_LONG_BITS - 8);
+ }
}
- tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32);
+ tcg_temp_free(t);
}
static void gen_PSHUFW(DisasContext *s, CPUX86State *env, X86DecodedInsn
*decode)
--
2.37.2
- Re: [PATCH v2 19/37] target/i386: reimplement 0x0f 0x60-0x6f, add AVX, (continued)
- [PATCH v2 04/37] target/i386: introduce insn_get_addr, Paolo Bonzini, 2022/09/20
- [PATCH v2 03/37] target/i386: REPZ and REPNZ are mutually exclusive, Paolo Bonzini, 2022/09/20
- [PATCH v2 16/37] target/i386: provide 3-operand versions of unary scalar helpers, Paolo Bonzini, 2022/09/20
- [PATCH v2 13/37] target/i386: Prepare ops_sse_header.h for 256 bit AVX, Paolo Bonzini, 2022/09/20
- [PATCH v2 12/37] target/i386: move scalar 0F 38 and 0F 3A instruction to new decoder, Paolo Bonzini, 2022/09/20
- [PATCH v2 10/37] target/i386: validate VEX prefixes via the instructions' exception classes, Paolo Bonzini, 2022/09/20
- [PATCH v2 09/37] target/i386: add AVX_EN hflag, Paolo Bonzini, 2022/09/20
- [PATCH v2 14/37] target/i386: extend helpers to support VEX.V 3- and 4- operand encodings, Paolo Bonzini, 2022/09/20
- [PATCH v2 27/37] target/i386: Use tcg gvec ops for pmovmskb,
Paolo Bonzini <=
- [PATCH v2 23/37] target/i386: reimplement 0x0f 0x70-0x77, add AVX, Paolo Bonzini, 2022/09/20
- [PATCH v2 34/37] target/i386: Enable AVX cpuid bits when using TCG, Paolo Bonzini, 2022/09/20
- [PATCH v2 31/37] target/i386: reimplement 0x0f 0x28-0x2f, add AVX, Paolo Bonzini, 2022/09/20
- [PATCH v2 29/37] target/i386: reimplement 0x0f 0xc2, 0xc4-0xc6, add AVX, Paolo Bonzini, 2022/09/20
- [PATCH v2 37/37] target/i386: remove old SSE decoder, Paolo Bonzini, 2022/09/20
- [PATCH v2 18/37] target/i386: Introduce 256-bit vector helpers, Paolo Bonzini, 2022/09/20
- [PATCH v2 11/37] target/i386: validate SSE prefixes directly in the decoding table, Paolo Bonzini, 2022/09/20