From 4ccadaf6cf87e4bda025852b835da9e30fa4ac3f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 3 Mar 2021 19:25:02 -0500 Subject: [PATCH] tcg: Use memset for large vector byte replication In f47db80cc07, we handled odd-sized tail clearing for the case of hosts that have vector operations, but did not handle the case of hosts that do not have vector ops. This was ok until e2e7168a214b, which changed the encoding of simd_desc such that the odd sizes are impossible. Add memset as a tcg helper, and use that for all out-of-line byte stores to vectors. This includes, but is not limited to, the tail clearing operation in question. Backports 6d3ef04893bdea3e7aa08be3cce5141902836a31 --- qemu/accel/tcg/tcg-runtime.h | 11 +++++++++++ qemu/include/exec/helper-proto.h | 3 +++ qemu/tcg/tcg-op-gvec.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/qemu/accel/tcg/tcg-runtime.h b/qemu/accel/tcg/tcg-runtime.h index 4eda24e6..2e36d6eb 100644 --- a/qemu/accel/tcg/tcg-runtime.h +++ b/qemu/accel/tcg/tcg-runtime.h @@ -28,6 +28,17 @@ DEF_HELPER_FLAGS_1(lookup_tb_ptr, TCG_CALL_NO_WG_SE, ptr, env) DEF_HELPER_FLAGS_1(exit_atomic, TCG_CALL_NO_WG, noreturn, env) +#ifndef IN_HELPER_PROTO +/* + * Pass calls to memset directly to libc, without a thunk in qemu. + * Do not re-declare memset, especially since we fudge the type here; + * we assume sizeof(void *) == sizeof(size_t), which is true for + * all supported hosts. + */ +#define helper_memset memset +DEF_HELPER_FLAGS_3(memset, TCG_CALL_NO_RWG, ptr, ptr, int, ptr) +#endif /* IN_HELPER_PROTO */ + #ifdef CONFIG_SOFTMMU DEF_HELPER_FLAGS_5(atomic_cmpxchgb, TCG_CALL_NO_WG, diff --git a/qemu/include/exec/helper-proto.h b/qemu/include/exec/helper-proto.h index 260c3978..7fd3499e 100644 --- a/qemu/include/exec/helper-proto.h +++ b/qemu/include/exec/helper-proto.h @@ -35,9 +35,12 @@ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ dh_ctype(t4), dh_ctype(t5), dh_ctype(t6), \ dh_ctype(t7)); +#define IN_HELPER_PROTO + #include "helper.h" #include "tcg-runtime.h" +#undef IN_HELPER_PROTO #undef DEF_HELPER_FLAGS_0 #undef DEF_HELPER_FLAGS_1 #undef DEF_HELPER_FLAGS_2 diff --git a/qemu/tcg/tcg-op-gvec.c b/qemu/tcg/tcg-op-gvec.c index e4cdfb9c..8071667a 100644 --- a/qemu/tcg/tcg-op-gvec.c +++ b/qemu/tcg/tcg-op-gvec.c @@ -539,6 +539,9 @@ static void do_dup(TCGContext *s, unsigned vece, uint32_t dofs, uint32_t oprsz, in_c = dup_const(vece, in_c); if (in_c == 0) { oprsz = maxsz; + vece = MO_8; + } else if (in_c == dup_const(MO_8, in_c)) { + vece = MO_8; } } @@ -620,6 +623,35 @@ static void do_dup(TCGContext *s, unsigned vece, uint32_t dofs, uint32_t oprsz, /* Otherwise implement out of line. */ t_ptr = tcg_temp_new_ptr(s); tcg_gen_addi_ptr(s, t_ptr, s->cpu_env, dofs); + + /* + * This may be expand_clr for the tail of an operation, e.g. + * oprsz == 8 && maxsz == 64. The size of the clear is misaligned + * wrt simd_desc and will assert. Simply pass all replicated byte + * stores through to memset. + */ + if (oprsz == maxsz && vece == MO_8) { + TCGv_ptr t_size = tcg_const_ptr(s, oprsz); + TCGv_i32 t_val; + + if (in_32) { + t_val = in_32; + } else if (in_64) { + t_val = tcg_temp_new_i32(s); + tcg_gen_extrl_i64_i32(s, t_val, in_64); + } else { + t_val = tcg_const_i32(s, in_c); + } + gen_helper_memset(s, t_ptr, t_ptr, t_val, t_size); + + if (!in_32) { + tcg_temp_free_i32(s, t_val); + } + tcg_temp_free_ptr(s, t_size); + tcg_temp_free_ptr(s, t_ptr); + return; + } + t_desc = tcg_const_i32(s, simd_desc(oprsz, maxsz, 0)); if (vece == MO_64) {