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.

Reply via email to