Commit Graph
5 Commits
Author SHA1 Message Date
Valiantsin DzerakhandClaude Opus 5.5 c2943970cc Merge the spin wait gates: they also end the fight hangs
The generator emits a guest poll such as `ldr w9, [x19]; cmp w9, #1; b.eq` as a plain C load, and clang hoists it out
of the loop: the lock wait in f_7001fa0e2c compiled to `cmp; jne; jmp .`, so a thread that found the lock held spun
forever after its holder released it. A fight run hung this way in 3 of 13 launches on an RX 9070, with the UBO
snapshot on and off; gdb showed the thread on that `jmp` in every sample. The gate is an opaque call on every
back-edge of the 868 loops tools/spin_waits.py lists, so each pass reloads memory: the exe goes from 182 self-jumps to
148, and 144 of those are the game's own `b .` instructions. 8 of 8 fight runs then passed; tests/diff/func.py with
--patches passed 5470 cases on 878 functions, and the four probes passed on 1.4.3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 20:05:44 +03:00
Valiantsin DzerakhandClaude Opus 5.5 27056b212a Keep NZCV in a local of each generated function instead of c->nzcv
Every flag-setting instruction packed N, Z, C and V into c->nzcv and every reader unpacked them. recomp/flags.py
now runs a reaching-definitions pass per function: a compare stores its operands in a local Flags F, and a reader
whose definitions are all of one kind computes its condition from them, so cmp and b.cond become one host compare.
CCMP, FCMP, MSR NZCV and ADCS write the packed form, which readers reached by several kinds also use. Calls and
returns publish nothing (AAPCS64 neither passes nor preserves NZCV); tail branches, falls into the next function and
br through rt_dispatch publish c->nzcv, since discovery can start a function inside another one. Functions with an
unresolved computed br keep flags in c->nzcv.

1.4.3 main: 492k direct and 89k packed flag reads, .text 342 -> 299 MiB. Fight bench (bench-fight2-2026-10-27b,
frames 5400-7500, uncapped) 13.15 and 13.63 ms vs 13.9 before. tests/flags_check.py checks the new helpers against
the packed ones; tests/diff/func.py no longer compares NZCV, which generated code leaves untouched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 18:07:58 +03:00
Valiantsin DzerakhandClaude Opus 5.5 e9216b8b49 Test functions with calls in tests/diff/func.py: every BL and BLR goes to one stub on both sides, which folds the registers at the call into a digest kept in the scratch buffer and sets X0-X18, NZCV and V0-V7 from it, so a register missing from the Cpu at a call or held across one fails the case
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:12:34 +03:00
Valiantsin DzerakhandClaude Opus 5.5 3984344635 Spin wait gates: tools/spin_waits.py (the nxnative search) lists the loops that only another thread can end, the patch tables carry them as spin lines (857 in 1.4.3, 864 in 1.2.1), the generator sends their back-edges through rt_spin_gate, and the gate pauses the core once per pass and hands the virtual core to a waiter after 50 us of polling (TOTK_SPIN, TOTK_SPIN_HANDOFF_US)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 15:51:47 +03:00
Valiantsin DzerakhandClaude Opus 5.5 19c9b648d1 Add the recompiler, Windows runtime, tools and docs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 22:27:54 +03:00