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.
This commit is contained in:
@@ -1412,9 +1412,26 @@ premise was wrong.**
|
||||
db's own `vptr_writes`. `unit_state` = slot 184 = `0x8226ADF0`, which indexes
|
||||
`[phase+324]` by `local[4]` and writes its answer to **`[phase+164]` =
|
||||
`special[0]`**. So: **result → `special[0]`, comparand popped → `special[1]`,
|
||||
then `cmp.i` + branch.** ▶️ **Still open:** the other 111 vtable slots are a
|
||||
then `cmp.i` + branch.** ~~▶️ **Still open:** the other 111 vtable slots are a
|
||||
lookup but unread; which comparand each site pushes (needs `push.i` tracked
|
||||
through the decode); the 35 non-vtable built-ins; the vtable's length. The condition lives in the `op10`/`op13` poll loop upstream of
|
||||
through the decode); the 35 non-vtable built-ins; the vtable's length.~~
|
||||
✅ **(2026-08-27) COMPARANDS RESOLVED — [structures/isl-conditions](structures/isl-conditions.md).**
|
||||
The deques are an **expression stack**: push the left operand, evaluate the
|
||||
right (result → `special[0]`), pop → `special[1]`, compare. Evidence: push/pop
|
||||
balance **1877/1877 across 28 stages with ZERO underflows**, and **319/319**
|
||||
Stage-02 `pop.i` sites are immediately followed by `cmp.i`. `isl.conditions()`
|
||||
now recovers **7563 condition sites disc-wide with 0.0 % left unresolved**
|
||||
(83.2 % have a built-in call as LHS, 99.7 % compare against a plain number).
|
||||
`data/isl-stage02-conditions.txt` finally has a generator
|
||||
(`isl_report.py conditions`); the other two artefacts regenerate identical.
|
||||
Top predicates: `hp_pct_test` 1955, `unit_state` 1257, `unit_relation` 796,
|
||||
`dist_lt` 450. 🟡 **1.6 % are WRONG:** 15 sites attribute the LHS to
|
||||
`end_coroutine`, which returns nothing — the tracker sets `special[0]` on every
|
||||
call, so those show a stale value. Fix = only set it for built-ins that write
|
||||
`[phase+164]`. ▶️ **Still open:** the 35 unnamed built-ins (`builtin16` 132
|
||||
sites, `builtin105` 117, `builtin103` 115 — each now a vtable-slot lookup);
|
||||
which condition guards each `END_PHASE` (needs the control flow between them);
|
||||
the vtable's length. The condition lives in the `op10`/`op13` poll loop upstream of
|
||||
the outro — e.g. phase 3 polls `unit_state(ADT308)` and branches back to
|
||||
`0xFEB4` until it passes. Artefact: `data/isl-stage02-phase-ends.txt`.
|
||||
* 🐛 **(2026-08-25) The nav fix is NOT fully reliable.** `dialog_up.py` works on
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
94
docs/re/structures/isl-conditions.md
Normal file
94
docs/re/structures/isl-conditions.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# ✅ 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`](isl-builtin-dispatch.md) 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.
|
||||
Reference in New Issue
Block a user