tcg/wasm32: add opt-in compiled-vs-TCI per-TB differential checker

Runs authoritative TCI first, snapshots its result, rewinds guest state,
runs the compiled TB as a disposable shadow, compares GPRs/DRAM, then
restores TCI. Opt-in via wasm_diff_enable(); normal execution unchanged.

Valid comparison required restoring all state a single TB can touch:
- full CPUNegativeOffsetState (the env-8 interrupt check sits before env)
- deep CPUTLB.f[].table / d[].fulltlb per MMU mode
- and skipping async cpu_exit() force-exit races.

Only side-effect-safe candidates compared (store TB, no general helper).
Result: 160k+ store-TB comparisons during reader-open, zero divergence.
Per-TB store codegen is exonerated; corruption is emergent across TBs.
This commit is contained in:
2026-07-22 16:05:41 -04:00
parent e45c1e2db1
commit 1473b7ab10
5 changed files with 323 additions and 4 deletions
+13
View File
@@ -41,6 +41,9 @@
#include "tb-context.h"
#include "internal-common.h"
#include "internal-target.h"
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
#include "../../tcg/wasm32.h"
#endif
/* -icount align implementation. */
@@ -173,6 +176,13 @@ uint32_t curr_cflags(CPUState *cpu)
cflags |= CF_NO_GOTO_TB;
}
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
/* Differential mode runs one TB per dispatch so wasm_cur_tb_pc stays exact. */
if (wasm_diff_on()) {
cflags |= CF_NO_GOTO_TB | CF_NO_GOTO_PTR;
}
#endif
return cflags;
}
@@ -455,6 +465,9 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
}
qemu_thread_jit_execute();
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
wasm_cur_tb_pc = itb->pc;
#endif
ret = tcg_qemu_tb_exec(cpu_env(cpu), tb_ptr);
cpu->neg.can_do_io = true;
qemu_plugin_disable_mem_helpers(cpu);