On Tue, 13 Oct 2026 09:00:41 PDT (-0700), [email protected] wrote:
On 10/13/2026 10:14 AM, Palmer Dabbelt wrote:On Tue, 13 Oct 2026 04:57:49 PDT (-0700), [email protected] wrote:On 10/2/2026 10:47 AM, Rick Richard wrote:With Ztso, plain loads and stores follow RVTSO, but the barriers around them use TCG_MO_ALL. That also orders a store before a later load, which TSO doesn't require, and is expensive: on x86 hosts it adds a locked instruction around every load and store in a multi-threaded guest.Thanks. I'm not quite sure why I had TCG_MO_ALL in there, I think maybe I just misread the TCG_MO_* vs TCG_BAR_* blurb? Reviewed-by: Palmer Dabbelt <[email protected]>The barrier after a load now only keeps later loads and stores behind it, and the barrier before a store only keeps earlier loads and stores ahead of it. That is all TSO needs.Fixes: 09c4e88759 ("RISC-V: Add support for Ztso")Signed-off-by: Rick Richard <[email protected]> ---Reviewed-by: Daniel Henrique Barboza <[email protected]>I found this while looking into why riscv64 guests were so much slower than aarch64 ones under bsd-user on FreeBSD. The default -cpu max enables Ztso, and turning it off with ztso=false accounted for most of the difference.Maybe we shouldn't default to Ztso, or at least not default to Ztso on host systems that themselves aren't TSO?I vote to disable it in the 'max' CPU. Changing the mem model from RVWMO to RVTSO seems like a decision users have to make in the command line, not something we decided to do because this particular CPU model must have all possible extensions enabled. In theory we could enable it depending on the host affinity with TSO, but I'd rather not create a precedent where a TCG CPU model delivers different extensions based on host capabilities. We have enough of that in the KVM driver.
Ya, that seems reasonable. I think the only issue is that TSO hosts will end up defacto TSO in the guest -- or at least I think they will, IIUC that is basicallly how things used to work because TCG didn't do any interesting memory reordering at compile time and thus the TSO-ness of the host essentially just bled through to the guest.
Thanks, DanielOn an x86-64 host the patch made xz almost four times faster and cut the time of a clang compile by about 30%, the same as running with ztso=false. The output didn't change. I also tested it on a Raspberry Pi 3B+, which is arm64 and doesn't give TSO ordering in hardware, to make sure the weaker barriers still hold up there. Everything ran correctly, and xz was about 12% faster. target/riscv/tcg/insn_trans/trans_rvi.c.inc | 4 ++-- target/riscv/tcg/insn_trans/trans_rvv.c.inc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target/riscv/tcg/insn_trans/trans_rvi.c.inc b/target/riscv/tcg/insn_trans/trans_rvi.c.inc index 40b4c9aa..d31e4295 100644 --- a/target/riscv/tcg/insn_trans/trans_rvi.c.inc +++ b/target/riscv/tcg/insn_trans/trans_rvi.c.inc @@ -424,7 +424,7 @@ static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop) } if (ctx->ztso) { - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); + tcg_gen_mb(TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_BAR_LDAQ); } return out; @@ -485,7 +485,7 @@ static bool gen_store_tl(DisasContext *ctx, arg_sb *a, MemOp memop) TCGv data = get_gpr(ctx, a->rs2, EXT_NONE); if (ctx->ztso) { - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); + tcg_gen_mb(TCG_MO_LD_ST | TCG_MO_ST_ST | TCG_BAR_STRL); } tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop); diff --git a/target/riscv/tcg/insn_trans/trans_rvv.c.inc b/target/riscv/tcg/insn_trans/trans_rvv.c.inc index a22e2cae..8c21ab87 100644 --- a/target/riscv/tcg/insn_trans/trans_rvv.c.inc +++ b/target/riscv/tcg/insn_trans/trans_rvv.c.inc @@ -731,7 +731,7 @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data, * around the loop. */ if (is_store && s->ztso) { - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); + tcg_gen_mb(TCG_MO_LD_ST | TCG_MO_ST_ST | TCG_BAR_STRL); } mark_vs_dirty(s); @@ -739,7 +739,7 @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data, fn(dest, mask, base, tcg_env, desc); if (!is_store && s->ztso) { - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); + tcg_gen_mb(TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_BAR_LDAQ); } finalize_rvv_inst(s);
