This repository has been archived on 2026-09-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Syplheed-Reborn/docs/re/structures/isl-conditions.md
Sylpheed RE agent eac5b3e22e re: resolve every ISL condition's comparand -- the clear conditions are readable
The deque ops are an EXPRESSION STACK: push the left operand, evaluate the right
(a built-in call, whose result lands in special[0]), pop the comparand back into
special[1], compare.  Tracking that through the linear decode is enough to recover
what each site tests.

Evidence the model is right, not just plausible:
  push vs pop across all 28 stages          1877 vs 1877
  files that underflow or end unbalanced    0 of 28
  Stage 02 pop.i sites followed by cmp.i    319 / 319
  ops immediately before a pop.i            call x313, cmp.a x6

isl.conditions() recovers 7563 condition sites disc-wide with 0.0% left as an
unresolved special[N]; 83.2% have a built-in call as the LHS and 99.7% compare
against a plain number.  Most-tested: hp_pct_test 1955, unit_state 1257,
unit_relation 796, dist_lt 450, unit_alive 413.

They read as conditions now:
  if unit_alive(TCN105) != 1
  if hp_pct_test(ADT308, 0) != 1
  if dist_lt(ADT308, TCN000, 15000) != 1      (world unit = 1 m, so 15 km)
  if unit_state(ADT308) == 1

data/isl-stage02-conditions.txt was a stale artefact with NO generator -- the thing
isl_report.py's docstring complained about.  It has one now (isl_report.py
conditions).  The calls and phase-ends artefacts both regenerate byte-identical, so
the change is additive.

Recorded rather than glossed: 15 of Stage 02's 965 sites (1.6%) attribute the LHS to
end_coroutine, which returns no value -- the tracker sets special[0] on EVERY call,
so those show a stale value and are wrong, not imprecise.  The fix is to set it only
for built-ins that write [phase+164], which the vtable work makes checkable.
2026-08-27 05:28:50 +00:00

4.0 KiB
Raw Blame History

✅ Every condition site, with its comparand — the clear conditions are readable

This is what the whole ISL chain was for. data/isl-stage02-conditions.txt has existed for a long time as a stale artefact with no generator — isl_report.py's own docstring says so. It has one now, and the conditions are resolved rather than printed as special[N].

✅ The deque ops are an expression stack

isl-bytecode.md names ops 21–24 push.i/push.f/pop.i/pop.f over deques at phase+44 / phase+64. What they are used for is the missing piece:

set.i  special[0] = 1
set.i  special[1] = special[0]
push.i                          ; save the comparand
set.i  local[0] = 1
set.i  local[4] = 0x49
call   unit_state(ADT308)       ; result -> special[0]   (clobbers it)
pop.i                           ; restore comparand -> special[1]
cmp.i  special[0], special[1]
beq    -> 0xFEB4

A textbook stack-machine lowering: push the left operand, evaluate the right, pop, compare. Tracking the stack through the decode is therefore enough to recover what every site actually tests.

The evidence it is a stack, not something else

check result
push vs pop across all 28 stages 1877 vs 1877
files where the deque underflows or ends unbalanced 0 of 28
Stage 02 pop.i sites immediately followed by cmp.i 319 / 319
ops immediately preceding a pop.i call ×313, cmp.a ×6

Perfect balance with zero underflow across 28 independent files is not something a wrong model produces, and pop.i → cmp.i at 319/319 makes pop.i a reliable marker for a condition site.

✅ Result — disc-wide

isl.conditions() walks the linear stream tracking special[], local[] and the stack, then reports each compare with its branch:

all 28 stages
condition sites 7 563
either side left unresolved as special[N] 0 — 0.0 %
LHS is a resolved built-in call 6 292 — 83.2 %
RHS is a plain number 7 544 — 99.7 %

Most-tested predicates disc-wide: hp_pct_test 1955, unit_state 1257, unit_relation 796, dist_lt 450, request_script_message 425, unit_alive 413, read_freg 187.

And they read as conditions:

0x032F4 ph1  if unit_alive(TCN105) != 1                    -> 0x3388
0x04D70 ph1  if unit_hp_pct(TCN001, Character_Player_Test) != 0 -> 0x51FC
0x2C4E0 ph3  if hp_pct_test(ADT308, 0) != 1                -> 0x2CF8C
0x30790 ph3  if dist_lt(ADT308, TCN000, 15000) != 1        -> 0x307B0
0x33FA0 ph3  if unit_state(ADT308) != 2                     -> 0x34030
0x349E0 ph3  if unit_state(ADT308) == 1                     -> 0x34A00

dist_lt(ADT308, TCN000, 15000) — with the world unit established as 1 metre, that is a 15 km proximity test.

🟡 A caveat the numbers themselves expose

15 of Stage 02's 965 sites (1.6 %) attribute the left-hand side to end_coroutine, which does not return a value. The tracker sets special[0] on every call, so where the right-hand side of a comparison was not actually a value-producing built-in, the LHS shown is a stale special[0] from an earlier call. Those sites are wrong, not merely imprecise.

The fix is to set special[0] only for built-ins that write [phase+164] — which isl-builtin-dispatch makes checkable, since 112 of 147 are vtable slots whose implementations can be tested for that store. Not done; recorded so the 1.6 % is not read as accurate.

🟡 Not settled

  • The 35 unnamed built-ins still print as builtinN — builtin103 (115 sites), builtin105 (117) and builtin16 (132) are the highest-traffic unknowns, and each is now a vtable-slot lookup away.
  • Which condition guards each END_PHASE. Every site is readable, but linking a condition to the phase exit it eventually reaches needs the control flow between them, which this listing does not follow.
  • Only Stage 02's artefact is committed; the other 27 generate from the same command but are not in the tree.