On Tue, Aug 18, 2026 at 5:51 PM Pierrick Bouvier <[email protected]> wrote: > > On 8/18/2026 10:42 AM, Matt Turner wrote: > > Every indirect branch that cannot use goto_tb ends in > > tcg_gen_lookup_and_goto_ptr(), which calls helper_lookup_tb_ptr(). For an > > emulated compiler that is 8.4 billion helper calls in a single translation > > unit: 24.6% of all TB exits take this path, because jsr/ret/jmp have a > > register destination and because goto_tb is restricted to same-page > > targets. > > > > The helper itself is already tight, but each call pays for a call frame, > > the can_do_io store, the get_tb_cpu_state() indirect call through > > TCGCPUOps, curr_cflags(), and a breakpoint check, before it gets to the > > jump cache probe that almost always hits (95.8% for this workload). > > > > Emit the probe inline instead. The destination PC is already in a TCG > > temp, and the flags and cflags the destination must match are constants at > > translation time, so the fast path is a hash, three guarded loads and a > > goto_ptr. Only a miss calls the helper, which still owns filling the cache. > > > > Two details matter for the generated code. The flags and cflags guards are > > folded into a single aligned 64-bit load and compare, since the fields are > > adjacent. And each path emits its own goto_ptr rather than branching to a > > shared one: a temp live across the label is spilled and reloaded on every > > dispatch, which cost 6.3% on its own. > > > > Measured with qemu-alpha running an emulated alpha gcc 16.2.0 compiling > > the SQLite 3.45.1 amalgamation (255k lines, -O2) on an x86-64 host, LTO > > build, on top of the preceding three patches: > > > > before: 1,402,816,253,499 instructions > > after: 890,713,633,237 instructions -36.51% > > > > before: 115.75s wall clock > > after: 84.44s wall clock -27.05% > > > > The gap between the two is the point at which this stops being a > > straight-line win: the helper call was highly predictable work that the > > host pipelined well, so removing it retires far fewer instructions than it > > saves time. IPC falls from 2.48 to 2.15 across this patch for that reason. > > > > Despite emitting more code, this also reduces instruction cache pressure, > > because a dispatch no longer jumps into qemu's .text and evicts translated > > code: > > > > before: 11,476,318,964 L1-icache-load-misses > > after: 6,990,186,701 L1-icache-load-misses -39.1% > > > > The mechanism is visible directly in a profile: helper_lookup_tb_ptr() > > falls from 30.97% of samples to 0.42%, and qemu's own .text falls from > > 38.9% to 5.4%, with the balance moving into generated code. > > > > Combined with the three preceding patches, against an unmodified LTO > > build, 1,647,901,588,726 instructions fall to 890,713,633,237, or -45.95%. > > The emulated compiler produces byte-identical output throughout. > > > > Open issues, hence RFC: > > > > - The flags/cflags guards use the *current* TB's values as constants. That > > assumes the CPU flags feeding get_tb_cpu_state() cannot change within a > > TB, and that curr_cflags() cannot change under a running TB (gdb > > attaching to enable single-step would). Both need to be established or > > the values need to be loaded at runtime. > > - tcg/tcg-op.c has no business including accel/tcg/tb-jmp-cache.h or > > knowing the CPUJumpCache layout. The probe likely belongs in accel/tcg > > with a small emit helper exported from tcg/. > > - The jump cache entry is read without qatomic_read(); entries are > > invalidated concurrently by setting tb to NULL. > > - Only wired up for alpha so far, and only for 64-bit guest PCs. > > > > Signed-off-by: Matt Turner <[email protected]> > > --- > > include/tcg/tcg-op-common.h | 2 + > > target/alpha/translate.c | 4 +- > > tcg/tcg-op.c | 79 +++++++++++++++++++++++++++++++++++++ > > 3 files changed, 83 insertions(+), 2 deletions(-) > > > > This change breaks following tcg test: > alpha-linux-user/gdbstub-follow-fork-mode-child > > Reproduce with: > ninja -C build && > make -C build/tests/tcg/alpha-linux-user/ && > make -C build/tests/tcg/alpha-linux-user/ run-gdbstub-follow-fork-mode-child > > Need gdb-multiarch and gcc-alpha-linux-gnu installed on your machine.
Thanks! I had gdb available, I apparently just needed to configure with `--cross-prefix-alpha=alpha-unknown-linux-gnu-` to get this test to run. Fixed locally.
