re: builtin80 is a command -- and finding that exposed an 11.75% bug in my tracker

Reading builtin80's body (0x82268460) to name it: it is NOT a predicate.  It
allocates a 20-byte object, stamps vtable 0x820A8CB0, magic 0xAB0311BA and the
unit's live object into it, pushes it onto a queue via the same helper push.i uses,
and returns 1 -- or 0 when the unit is absent.  A command.

That made the conditions listing impossible: it showed a six-way switch
`if builtin80(TCT206) == 0 … == 5` on a function returning 1 or 0.  Disassembling the
site shows two unconditional `jmp`s between the call and the compare, so 0x1B6C0 is
reached ONLY by a branch and its special[0] has nothing to do with builtin80.

op12 is unconditional -- the next instruction is never reached by fall-through -- and
the tracker walked through it exactly as it had walked through end_coroutine.  Last
iteration I fixed the instance and not the class, leaving 22x more bad sites in place
than the fix removed.

A/B over all 28 stages, 7563 sites, resetting at jmp as well:
  sites whose operands change              889  (11.75%)
  LHS unresolved, before -> after     34 (0.45%) -> 756 (10.00%)

So the previous commit's headline "0.0% unresolved" was a MISSING CHECK, not a strong
result: the linear walk always had some value to report, and reporting it was the bug.
10% is the honest figure and the other 90% is trustworthy for a reason.

Also corrected: isl-unit-args.md illustrated its diff with 0x1B6C0, which is one of
the bogus sites.  The UNIT_ARG result itself stands -- it came from reading
implementations, not from this listing -- but the example was picked from bad output.

Not done, and said so: recovering the 756 needs a dataflow join over each block's
actual predecessors, a CFG fixpoint rather than a linear pass.  The branch targets are
all known so the CFG is available; the analysis is not written.

calls and phase-ends regenerate byte-identical; conditions changes on 187 lines.
This commit is contained in:
Sylpheed RE agent
2026-08-27 05:53:20 +00:00
parent 126539b875
commit 58b404aef4
5 changed files with 192 additions and 107 deletions

View File

@@ -1434,9 +1434,17 @@ premise was wrong.**
over 28 stages: exactly **34 of 7563** sites change, **34 → 0** with an
`end_coroutine` LHS, and the two counts being equal proves the leak was
confined to them — the other 7529 were never affected. They now print an
explicit unknown. 🟡 Recoverable but not recovered: the RHS of each is still
exact, and seeding the tracker at coroutine ENTRIES (`start_coroutine`'s target
is staged slot 0) would resolve the LHS. ▶️ **Still open:** the 35 unnamed built-ins (`builtin16` 132
explicit unknown.
🔴 **(2026-08-27) THAT FIX WAS TOO NARROW — I fixed the instance, not the class.**
`op12 jmp` is unconditional, so the next instruction is never reached by
fall-through either, and the tracker walked through it exactly as it had walked
through `end_coroutine`. Exposed by another impossible output: a six-way switch
on `builtin80`, which returns only 1 or 0. A/B over 28 stages: **889 of 7563
sites (11.75 %) change**, and unresolved goes **34 (0.45 %) → 756 (10.00 %)**.
The earlier "0.0 % unresolved" was a MISSING CHECK, not a strong result.
🟡 Recovering the 756 needs a real dataflow **join over each block's actual
predecessors** (a CFG fixpoint) — the branch targets are all known, the analysis
is not written. ▶️ **Still open:** the 35 unnamed built-ins (`builtin16` 132
sites, `builtin105` 117, `builtin103` 115 — each now a vtable-slot lookup);
**(2026-08-27) partial — [structures/isl-unit-args](structures/isl-unit-args.md):**
reading the implementations shows **55** built-ins take a unit at `local[4]`,
@@ -1448,7 +1456,13 @@ premise was wrong.**
`slot0 == 1` in 100.0 % / 100.0 % / **2.5 %**. Artefacts: calls + phase-ends
byte-identical, conditions changes on 28 sites (raw number → unit name).
Still unnamed: all 24. `builtin103` is a predicate over `[phase+10152]` and
`[phase+10156]` (no unit arg); `builtin105` tests a unit record's `+16` == 4.
`[phase+10156]` (no unit arg); `builtin105` tests a unit record's `+16` == 4
(`isl-builtins.md` documents `rec+16` as the unit STATE, 2 = active).
🔴 **(2026-08-27) `builtin80` is a COMMAND, not a predicate** (`0x82268460`):
it allocates a 20-byte object, stamps vtable `0x820A8CB0` + magic `0xAB0311BA`
+ the unit's live object, pushes it on a queue via the `push.i` helper, and
returns 1 (or 0 if the unit is absent). Finding that **exposed a much bigger
bug in my own condition tracker** — see the entry below.
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

View File

@@ -16,12 +16,9 @@ the right-hand side is evaluated (its result lands in `special[0]`),
unit_relation 52
builtin103 39
builtin105 38
builtin80 28
request_script_message 26
read_freg 10
unit_hp_pct 9
builtin7 9
builtin83 2
builtin99 1
## phase 1 — 435 sites
@@ -29,17 +26,17 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x0032F4 if unit_alive(TCN105) != 1 -> 0x3388
0x0044A4 if unit_alive(TCN105) != 1 -> 0x4538
0x004D70 if unit_hp_pct(TCN001, Character_Player_Test) != 0 -> 0x51FC
0x005110 if request_script_message(MSG_VOICE_D_257, 2, 1, 9, 1, -1) == 0 -> 0x4E68
0x005124 if request_script_message(MSG_VOICE_D_257, 2, 1, 9, 1, -1) == 1 -> 0x4F10
0x005138 if request_script_message(MSG_VOICE_D_257, 2, 1, 9, 1, -1) == 2 -> 0x4FB8
0x00514C if request_script_message(MSG_VOICE_D_257, 2, 1, 9, 1, -1) == 3 -> 0x5060
0x005110 if <unknown: block entered by a branch, not by fall-through> == 0 -> 0x4E68
0x005124 if <unknown: block entered by a branch, not by fall-through> == 1 -> 0x4F10
0x005138 if <unknown: block entered by a branch, not by fall-through> == 2 -> 0x4FB8
0x00514C if <unknown: block entered by a branch, not by fall-through> == 3 -> 0x5060
0x00523C if hp_pct_test(TCN004, 0) != 1 -> 0x5840
0x00572C if request_script_message(MSG_VOICE_D_261, 2, 1, 9, 1, -1) == 0 -> 0x5334
0x005740 if request_script_message(MSG_VOICE_D_261, 2, 1, 9, 1, -1) == 1 -> 0x53DC
0x005754 if request_script_message(MSG_VOICE_D_261, 2, 1, 9, 1, -1) == 2 -> 0x5484
0x005768 if request_script_message(MSG_VOICE_D_261, 2, 1, 9, 1, -1) == 3 -> 0x552C
0x00577C if request_script_message(MSG_VOICE_D_261, 2, 1, 9, 1, -1) == 4 -> 0x55D4
0x005790 if request_script_message(MSG_VOICE_D_261, 2, 1, 9, 1, -1) == 5 -> 0x567C
0x00572C if <unknown: block entered by a branch, not by fall-through> == 0 -> 0x5334
0x005740 if <unknown: block entered by a branch, not by fall-through> == 1 -> 0x53DC
0x005754 if <unknown: block entered by a branch, not by fall-through> == 2 -> 0x5484
0x005768 if <unknown: block entered by a branch, not by fall-through> == 3 -> 0x552C
0x00577C if <unknown: block entered by a branch, not by fall-through> == 4 -> 0x55D4
0x005790 if <unknown: block entered by a branch, not by fall-through> == 5 -> 0x567C
0x005888 if read_freg(0) <= 210 -> 0x6028
0x0058DC if hp_pct_test(ADT102, 0) != 1 -> 0x6028
0x005930 if hp_pct_test(ADT107, 0) != 1 -> 0x6028
@@ -177,7 +174,7 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x00C668 if unit_state(ADN111) != 1 -> 0xC6E8
0x00C72C if unit_state(ADN112) != 1 -> 0xC7AC
0x00C7F0 if unit_state(ADS151) != 1 -> 0xC870
0x00C930 if hp_pct_test(TCN004, 50, 26) != 1 -> 0xEC70
0x00C930 if hp_pct_test(TCN004, 50) != 1 -> 0xEC70
0x00C944 if global[20] > 25 -> 0xEC70
0x00C99C if unit_state(ADN101) != 1 -> 0xCA08
0x00C9EC if unit_relation(ADN101, TCN004) != 1 -> 0xCA08
@@ -273,21 +270,21 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x0103D0 if unit_state(ADT113) == 1 -> 0x10438
0x010484 if unit_state(ADN114) == 1 -> 0x104EC
0x010538 if unit_state(ADN115) == 1 -> 0x105A0
0x0105C4 if <unknown: reached after a coroutine boundary> == 28 -> 0xFB1C
0x0105D8 if <unknown: reached after a coroutine boundary> == 29 -> 0xFBD0
0x0105EC if <unknown: reached after a coroutine boundary> == 30 -> 0xFC84
0x010600 if <unknown: reached after a coroutine boundary> == 31 -> 0xFD38
0x010614 if <unknown: reached after a coroutine boundary> == 32 -> 0xFDEC
0x010628 if <unknown: reached after a coroutine boundary> == 33 -> 0xFEA0
0x01063C if <unknown: reached after a coroutine boundary> == 34 -> 0xFF54
0x010650 if <unknown: reached after a coroutine boundary> == 35 -> 0x10008
0x010664 if <unknown: reached after a coroutine boundary> == 36 -> 0x100BC
0x010678 if <unknown: reached after a coroutine boundary> == 37 -> 0x10170
0x01068C if <unknown: reached after a coroutine boundary> == 38 -> 0x10224
0x0106A0 if <unknown: reached after a coroutine boundary> == 39 -> 0x102D8
0x0106B4 if <unknown: reached after a coroutine boundary> == 40 -> 0x1038C
0x0106C8 if <unknown: reached after a coroutine boundary> == 41 -> 0x10440
0x0106DC if <unknown: reached after a coroutine boundary> == 42 -> 0x104F4
0x0105C4 if <unknown: block entered by a branch, not by fall-through> == 28 -> 0xFB1C
0x0105D8 if <unknown: block entered by a branch, not by fall-through> == 29 -> 0xFBD0
0x0105EC if <unknown: block entered by a branch, not by fall-through> == 30 -> 0xFC84
0x010600 if <unknown: block entered by a branch, not by fall-through> == 31 -> 0xFD38
0x010614 if <unknown: block entered by a branch, not by fall-through> == 32 -> 0xFDEC
0x010628 if <unknown: block entered by a branch, not by fall-through> == 33 -> 0xFEA0
0x01063C if <unknown: block entered by a branch, not by fall-through> == 34 -> 0xFF54
0x010650 if <unknown: block entered by a branch, not by fall-through> == 35 -> 0x10008
0x010664 if <unknown: block entered by a branch, not by fall-through> == 36 -> 0x100BC
0x010678 if <unknown: block entered by a branch, not by fall-through> == 37 -> 0x10170
0x01068C if <unknown: block entered by a branch, not by fall-through> == 38 -> 0x10224
0x0106A0 if <unknown: block entered by a branch, not by fall-through> == 39 -> 0x102D8
0x0106B4 if <unknown: block entered by a branch, not by fall-through> == 40 -> 0x1038C
0x0106C8 if <unknown: block entered by a branch, not by fall-through> == 41 -> 0x10440
0x0106DC if <unknown: block entered by a branch, not by fall-through> == 42 -> 0x104F4
0x010728 if builtin103() != 0 -> 0x10748
0x010788 if hp_pct_test(TCN004, 30) != 1 -> 0x108D4
0x010814 if dist_lt(TCN004, TCN001, 10000) == 1 -> 0x108D4
@@ -469,10 +466,10 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x018FFC if hp_pct_test(ADN208, 0) != 1 -> 0x19090
0x019124 if builtin103() != 1 -> 0x1915C
0x0191CC if unit_hp_pct(TCN001, Character_Player_Test) != 0 -> 0x19658
0x01956C if request_script_message(MSG_VOICE_D_257, 2, 1, 9, 1, -1) == 0 -> 0x192C4
0x019580 if request_script_message(MSG_VOICE_D_257, 2, 1, 9, 1, -1) == 1 -> 0x1936C
0x019594 if request_script_message(MSG_VOICE_D_257, 2, 1, 9, 1, -1) == 2 -> 0x19414
0x0195A8 if request_script_message(MSG_VOICE_D_257, 2, 1, 9, 1, -1) == 3 -> 0x194BC
0x01956C if <unknown: block entered by a branch, not by fall-through> == 0 -> 0x192C4
0x019580 if <unknown: block entered by a branch, not by fall-through> == 1 -> 0x1936C
0x019594 if <unknown: block entered by a branch, not by fall-through> == 2 -> 0x19414
0x0195A8 if <unknown: block entered by a branch, not by fall-through> == 3 -> 0x194BC
0x019698 if hp_pct_test(TCT206, 0) != 1 -> 0x1994C
0x0199C8 if builtin7(TCT206, 1, Route_TCT206_p2S, 4294967295, 500) == 1 -> 0x19A38
0x019A24 if read_freg(0) <= 600 -> 0x19A44
@@ -531,21 +528,21 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x01B0D4 if dist_lt(TCT206, ADN232, 15000) != 1 -> 0x1B138
0x01B180 if hp_pct_test(ADN201, 0) == 1 -> 0x1B220
0x01B20C if dist_lt(TCT206, ADN201, 20000) == 1 -> 0x1B250
0x01B298 if hp_pct_test(ADN202, 0, 0) == 1 -> 0x1B338
0x01B298 if hp_pct_test(ADN202, 0) == 1 -> 0x1B338
0x01B324 if dist_lt(TCT206, ADN202, 20000) == 1 -> 0x1B368
0x01B3B0 if hp_pct_test(ADN207, 0, 0) == 1 -> 0x1B450
0x01B3B0 if hp_pct_test(ADN207, 0) == 1 -> 0x1B450
0x01B43C if dist_lt(TCT206, ADN207, 20000) == 1 -> 0x1B480
0x01B4C8 if hp_pct_test(ADN231, 0, 0) == 1 -> 0x1B568
0x01B4C8 if hp_pct_test(ADN231, 0) == 1 -> 0x1B568
0x01B554 if dist_lt(TCT206, ADN231, 20000) == 1 -> 0x1B598
0x01B5E0 if hp_pct_test(ADN232, 0, 0) == 1 -> 0x1B680
0x01B5E0 if hp_pct_test(ADN232, 0) == 1 -> 0x1B680
0x01B66C if dist_lt(TCT206, ADN232, 20000) == 1 -> 0x1B6B0
0x01B6C0 if builtin80(TCT206) == 0 -> 0x1AC74
0x01B6D4 if builtin80(TCT206) == 1 -> 0x1B140
0x01B6E8 if builtin80(TCT206) == 2 -> 0x1B258
0x01B6FC if builtin80(TCT206) == 3 -> 0x1B370
0x01B710 if builtin80(TCT206) == 4 -> 0x1B488
0x01B724 if builtin80(TCT206) == 5 -> 0x1B5A0
0x01B77C if hp_pct_test(TCN207, 0, 0) != 1 -> 0x1B79C
0x01B6C0 if <unknown: block entered by a branch, not by fall-through> == 0 -> 0x1AC74
0x01B6D4 if <unknown: block entered by a branch, not by fall-through> == 1 -> 0x1B140
0x01B6E8 if <unknown: block entered by a branch, not by fall-through> == 2 -> 0x1B258
0x01B6FC if <unknown: block entered by a branch, not by fall-through> == 3 -> 0x1B370
0x01B710 if <unknown: block entered by a branch, not by fall-through> == 4 -> 0x1B488
0x01B724 if <unknown: block entered by a branch, not by fall-through> == 5 -> 0x1B5A0
0x01B77C if hp_pct_test(TCN207, 0) != 1 -> 0x1B79C
0x01B7D4 if unit_alive(ADN201) != 1 -> 0x1B8A4
0x01B840 if dist_lt(TCN207, ADN201, 15000) != 1 -> 0x1B8A4
0x01B8C8 if unit_alive(ADN202) != 1 -> 0x1B998
@@ -558,21 +555,21 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x01BC10 if dist_lt(TCN207, ADN232, 15000) != 1 -> 0x1BC74
0x01BCBC if hp_pct_test(ADN201, 0) == 1 -> 0x1BD5C
0x01BD48 if dist_lt(TCN207, ADN201, 20000) == 1 -> 0x1BD8C
0x01BDD4 if hp_pct_test(ADN202, 0, 0) == 1 -> 0x1BE74
0x01BDD4 if hp_pct_test(ADN202, 0) == 1 -> 0x1BE74
0x01BE60 if dist_lt(TCN207, ADN202, 20000) == 1 -> 0x1BEA4
0x01BEEC if hp_pct_test(ADN207, 0, 0) == 1 -> 0x1BF8C
0x01BEEC if hp_pct_test(ADN207, 0) == 1 -> 0x1BF8C
0x01BF78 if dist_lt(TCN207, ADN207, 20000) == 1 -> 0x1BFBC
0x01C004 if hp_pct_test(ADN231, 0, 0) == 1 -> 0x1C0A4
0x01C004 if hp_pct_test(ADN231, 0) == 1 -> 0x1C0A4
0x01C090 if dist_lt(TCN207, ADN231, 20000) == 1 -> 0x1C0D4
0x01C11C if hp_pct_test(ADN232, 0, 0) == 1 -> 0x1C1BC
0x01C11C if hp_pct_test(ADN232, 0) == 1 -> 0x1C1BC
0x01C1A8 if dist_lt(TCN207, ADN232, 20000) == 1 -> 0x1C1EC
0x01C1FC if builtin80(TCN207) == 0 -> 0x1B7B0
0x01C210 if builtin80(TCN207) == 1 -> 0x1BC7C
0x01C224 if builtin80(TCN207) == 2 -> 0x1BD94
0x01C238 if builtin80(TCN207) == 3 -> 0x1BEAC
0x01C24C if builtin80(TCN207) == 4 -> 0x1BFC4
0x01C260 if builtin80(TCN207) == 5 -> 0x1C0DC
0x01C2B8 if hp_pct_test(TCN208, 0, 0) != 1 -> 0x1C2D8
0x01C1FC if <unknown: block entered by a branch, not by fall-through> == 0 -> 0x1B7B0
0x01C210 if <unknown: block entered by a branch, not by fall-through> == 1 -> 0x1BC7C
0x01C224 if <unknown: block entered by a branch, not by fall-through> == 2 -> 0x1BD94
0x01C238 if <unknown: block entered by a branch, not by fall-through> == 3 -> 0x1BEAC
0x01C24C if <unknown: block entered by a branch, not by fall-through> == 4 -> 0x1BFC4
0x01C260 if <unknown: block entered by a branch, not by fall-through> == 5 -> 0x1C0DC
0x01C2B8 if hp_pct_test(TCN208, 0) != 1 -> 0x1C2D8
0x01C310 if unit_alive(ADN201) != 1 -> 0x1C3E0
0x01C37C if dist_lt(TCN208, ADN201, 15000) != 1 -> 0x1C3E0
0x01C404 if unit_alive(ADN202) != 1 -> 0x1C4D4
@@ -585,20 +582,20 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x01C74C if dist_lt(TCN208, ADN232, 15000) != 1 -> 0x1C7B0
0x01C7F8 if hp_pct_test(ADN201, 0) == 1 -> 0x1C898
0x01C884 if dist_lt(TCN208, ADN201, 20000) == 1 -> 0x1C8C8
0x01C910 if hp_pct_test(ADN202, 0, 0) == 1 -> 0x1C9B0
0x01C910 if hp_pct_test(ADN202, 0) == 1 -> 0x1C9B0
0x01C99C if dist_lt(TCN208, ADN202, 20000) == 1 -> 0x1C9E0
0x01CA28 if hp_pct_test(ADN207, 0, 0) == 1 -> 0x1CAC8
0x01CA28 if hp_pct_test(ADN207, 0) == 1 -> 0x1CAC8
0x01CAB4 if dist_lt(TCN208, ADN207, 20000) == 1 -> 0x1CAF8
0x01CB40 if hp_pct_test(ADN231, 0, 0) == 1 -> 0x1CBE0
0x01CB40 if hp_pct_test(ADN231, 0) == 1 -> 0x1CBE0
0x01CBCC if dist_lt(TCN208, ADN231, 20000) == 1 -> 0x1CC10
0x01CC58 if hp_pct_test(ADN232, 0, 0) == 1 -> 0x1CCF8
0x01CC58 if hp_pct_test(ADN232, 0) == 1 -> 0x1CCF8
0x01CCE4 if dist_lt(TCN208, ADN232, 20000) == 1 -> 0x1CD28
0x01CD38 if builtin80(TCN208) == 0 -> 0x1C2EC
0x01CD4C if builtin80(TCN208) == 1 -> 0x1C7B8
0x01CD60 if builtin80(TCN208) == 2 -> 0x1C8D0
0x01CD74 if builtin80(TCN208) == 3 -> 0x1C9E8
0x01CD88 if builtin80(TCN208) == 4 -> 0x1CB00
0x01CD9C if builtin80(TCN208) == 5 -> 0x1CC18
0x01CD38 if <unknown: block entered by a branch, not by fall-through> == 0 -> 0x1C2EC
0x01CD4C if <unknown: block entered by a branch, not by fall-through> == 1 -> 0x1C7B8
0x01CD60 if <unknown: block entered by a branch, not by fall-through> == 2 -> 0x1C8D0
0x01CD74 if <unknown: block entered by a branch, not by fall-through> == 3 -> 0x1C9E8
0x01CD88 if <unknown: block entered by a branch, not by fall-through> == 4 -> 0x1CB00
0x01CD9C if <unknown: block entered by a branch, not by fall-through> == 5 -> 0x1CC18
0x01D200 if hp_pct_test(ADN201, 0) != 1 -> 0x1D244
0x01D27C if unit_alive(TCN207) != 1 -> 0x1D34C
0x01D2E8 if dist_lt(ADN201, TCN207, 15000) != 1 -> 0x1D34C
@@ -609,17 +606,17 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x01D658 if builtin7(ADN201, 1, Route_ADN201_p2S, 4294967295, 500) != 1 -> 0x1D6F8
0x01D738 if hp_pct_test(TCN207, 0) == 1 -> 0x1D7D8
0x01D7C4 if dist_lt(ADN201, TCN207, 20000) == 1 -> 0x1D808
0x01D880 if builtin7(ADN201, 1, Route_ADN201_p2S, 4294967295, 500, 0) != 1 -> 0x1D920
0x01D880 if builtin7(ADN201, 1, Route_ADN201_p2S, 4294967295, 500) != 1 -> 0x1D920
0x01D960 if hp_pct_test(TCN208, 0) == 1 -> 0x1DA00
0x01D9EC if dist_lt(ADN201, TCN208, 20000) == 1 -> 0x1DA30
0x01DAA8 if builtin7(ADN201, 1, Route_ADN201_p2S, 4294967295, 500, 0) != 1 -> 0x1DB48
0x01DAA8 if builtin7(ADN201, 1, Route_ADN201_p2S, 4294967295, 500) != 1 -> 0x1DB48
0x01DBC0 if dist_lt(ADN201, TCT206, 20000) == 1 -> 0x1DC04
0x01DC1C if builtin80(ADN201) == 0 -> 0x1D258
0x01DC30 if builtin80(ADN201) == 1 -> 0x1D5E8
0x01DC44 if builtin80(ADN201) == 2 -> 0x1D810
0x01DC58 if builtin80(ADN201) == 3 -> 0x1DA38
0x01DC6C if builtin80(ADN201) == 4 -> 0x1DC0C
0x01DCC4 if hp_pct_test(ADN202, 0, 0) != 1 -> 0x1DD08
0x01DC1C if <unknown: block entered by a branch, not by fall-through> == 0 -> 0x1D258
0x01DC30 if <unknown: block entered by a branch, not by fall-through> == 1 -> 0x1D5E8
0x01DC44 if <unknown: block entered by a branch, not by fall-through> == 2 -> 0x1D810
0x01DC58 if <unknown: block entered by a branch, not by fall-through> == 3 -> 0x1DA38
0x01DC6C if <unknown: block entered by a branch, not by fall-through> == 4 -> 0x1DC0C
0x01DCC4 if hp_pct_test(ADN202, 0) != 1 -> 0x1DD08
0x01DD4C if hp_pct_test(ADN207, 0) != 1 -> 0x1DD6C
0x01DDA4 if unit_alive(TCN207) != 1 -> 0x1DE74
0x01DE10 if dist_lt(ADN207, TCN207, 15000) != 1 -> 0x1DE74
@@ -632,18 +629,18 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x01E27C if unit_alive(TCN208) != 1 -> 0x1E31C
0x01E3C4 if hp_pct_test(TCN207, 0) == 1 -> 0x1E464
0x01E450 if dist_lt(ADN207, TCN207, 20000) == 1 -> 0x1E494
0x01E50C if builtin7(ADN207, 1, Route_ADN207_p2S, 3, 55, 0) != 1 -> 0x1E64C
0x01E50C if builtin7(ADN207, 1, Route_ADN207_p2S, 3, 55) != 1 -> 0x1E64C
0x01E544 if unit_alive(TCN208) != 1 -> 0x1E5E4
0x01E68C if hp_pct_test(TCN208, 0) == 1 -> 0x1E72C
0x01E718 if dist_lt(ADN207, TCN208, 20000) == 1 -> 0x1E75C
0x01E7D4 if builtin7(ADN207, 1, Route_ADN207_p2S, 3, 55, 0) != 1 -> 0x1E914
0x01E7D4 if builtin7(ADN207, 1, Route_ADN207_p2S, 3, 55) != 1 -> 0x1E914
0x01E80C if unit_alive(TCN208) != 1 -> 0x1E8AC
0x01E98C if dist_lt(ADN207, TCT206, 20000) == 1 -> 0x1E9D0
0x01E9E8 if builtin80(ADN207) == 0 -> 0x1DD80
0x01E9FC if builtin80(ADN207) == 1 -> 0x1E1D4
0x01EA10 if builtin80(ADN207) == 2 -> 0x1E49C
0x01EA24 if builtin80(ADN207) == 3 -> 0x1E764
0x01EA38 if builtin80(ADN207) == 4 -> 0x1E9D8
0x01E9E8 if <unknown: block entered by a branch, not by fall-through> == 0 -> 0x1DD80
0x01E9FC if <unknown: block entered by a branch, not by fall-through> == 1 -> 0x1E1D4
0x01EA10 if <unknown: block entered by a branch, not by fall-through> == 2 -> 0x1E49C
0x01EA24 if <unknown: block entered by a branch, not by fall-through> == 3 -> 0x1E764
0x01EA38 if <unknown: block entered by a branch, not by fall-through> == 4 -> 0x1E9D8
0x01F78C if unit_state(ADN201) != 1 -> 0x1F7F8
0x01F7E4 if unit_state(TCT206) == 1 -> 0x1F804
0x01F85C if dist_lt(ADN201, TCT206, 10000) != 1 -> 0x1FA7C
@@ -773,17 +770,17 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x02B0D8 if unit_alive(TCN002) != 1 -> 0x2B20C
0x02B230 if unit_alive(TCN003) != 1 -> 0x2B310
0x02B4F8 if unit_hp_pct(TCN001, Character_Player_Test) != 0 -> 0x2B984
0x02B898 if request_script_message(MSG_VOICE_D_257, 2, 1, 9, 1, -1) == 0 -> 0x2B5F0
0x02B8AC if request_script_message(MSG_VOICE_D_257, 2, 1, 9, 1, -1) == 1 -> 0x2B698
0x02B8C0 if request_script_message(MSG_VOICE_D_257, 2, 1, 9, 1, -1) == 2 -> 0x2B740
0x02B8D4 if request_script_message(MSG_VOICE_D_257, 2, 1, 9, 1, -1) == 3 -> 0x2B7E8
0x02B898 if <unknown: block entered by a branch, not by fall-through> == 0 -> 0x2B5F0
0x02B8AC if <unknown: block entered by a branch, not by fall-through> == 1 -> 0x2B698
0x02B8C0 if <unknown: block entered by a branch, not by fall-through> == 2 -> 0x2B740
0x02B8D4 if <unknown: block entered by a branch, not by fall-through> == 3 -> 0x2B7E8
0x02B9C4 if hp_pct_test(TCN004, 0) != 1 -> 0x2BFC8
0x02BEB4 if request_script_message(MSG_VOICE_D_261, 2, 1, 9, 1, -1) == 0 -> 0x2BABC
0x02BEC8 if request_script_message(MSG_VOICE_D_261, 2, 1, 9, 1, -1) == 1 -> 0x2BB64
0x02BEDC if request_script_message(MSG_VOICE_D_261, 2, 1, 9, 1, -1) == 2 -> 0x2BC0C
0x02BEF0 if request_script_message(MSG_VOICE_D_261, 2, 1, 9, 1, -1) == 3 -> 0x2BCB4
0x02BF04 if request_script_message(MSG_VOICE_D_261, 2, 1, 9, 1, -1) == 4 -> 0x2BD5C
0x02BF18 if request_script_message(MSG_VOICE_D_261, 2, 1, 9, 1, -1) == 5 -> 0x2BE04
0x02BEB4 if <unknown: block entered by a branch, not by fall-through> == 0 -> 0x2BABC
0x02BEC8 if <unknown: block entered by a branch, not by fall-through> == 1 -> 0x2BB64
0x02BEDC if <unknown: block entered by a branch, not by fall-through> == 2 -> 0x2BC0C
0x02BEF0 if <unknown: block entered by a branch, not by fall-through> == 3 -> 0x2BCB4
0x02BF04 if <unknown: block entered by a branch, not by fall-through> == 4 -> 0x2BD5C
0x02BF18 if <unknown: block entered by a branch, not by fall-through> == 5 -> 0x2BE04
0x02BFC8 if global[112] < 4 -> 0x2C1F8
0x02C240 if read_freg(0) <= 300 -> 0x2CF8C
0x02C294 if hp_pct_test(ADT301, 0) != 1 -> 0x2CF8C
@@ -846,8 +843,8 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x02F6B8 if global[120] != 0 -> 0x2F780
0x02F6CC if global[124] != 1 -> 0x2F780
0x02F830 if global[108] != 1 -> 0x2F9FC
0x02F9C8 if request_script_message(MSG_VOICE_A_223, 2, 0, 8, 1, -1) == 0 -> 0x2F870
0x02F9DC if request_script_message(MSG_VOICE_A_223, 2, 0, 8, 1, -1) == 1 -> 0x2F918
0x02F9C8 if <unknown: block entered by a branch, not by fall-through> == 0 -> 0x2F870
0x02F9DC if <unknown: block entered by a branch, not by fall-through> == 1 -> 0x2F918
0x02FA44 if 8 < 1 -> 0x2FBC8
0x02FC10 if 8 < 3 -> 0x2FCF4
0x02FD3C if 8 < 4 -> 0x2FE20
@@ -913,7 +910,7 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x032AF8 if unit_state(ADT307) != 1 -> 0x32B78
0x032BBC if unit_state(ADT308) != 1 -> 0x32C3C
0x032C80 if unit_state(ADS351) != 1 -> 0x32D00
0x032DDC if dist_lt(TCN001, TCN099, 8000, 8) != 1 -> 0x32E9C
0x032DDC if dist_lt(TCN001, TCN099, 8000) != 1 -> 0x32E9C
0x032F00 if unit_hp_pct(TCN001, Character_Player_Test) <= 50 -> 0x32FD4
0x03301C if unit_state(ADS351) == 1 -> 0x3303C
0x033094 if dist_lt(TCN001, ADS351, 5000) != 1 -> 0x33154
@@ -992,5 +989,5 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x034968 if unit_state(ADT307) == 1 -> 0x34988
0x034988 if global[20] != 7 -> 0x34A00
0x0349E0 if unit_state(ADT308) == 1 -> 0x34A00
0x034A90 if builtin83(209) == 1 -> 0x34A30
0x034AA4 if builtin83(209) == 2 -> 0x34A5C
0x034A90 if <unknown: block entered by a branch, not by fall-through> == 1 -> 0x34A30
0x034AA4 if <unknown: block entered by a branch, not by fall-through> == 2 -> 0x34A5C

View File

@@ -47,10 +47,13 @@ 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 % |
| **LHS honestly unresolved** | **75610.0 %** |
| RHS is a plain number | 7 544 — 99.7 % |
🔴 **The first version of this table claimed 0.0 % unresolved. That was wrong**
see *The correction* below. ~11.75 % of the operands it reported were derived
from state that leaked across an unconditional jump.
**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.
@@ -128,3 +131,55 @@ done.
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.
## 🔴 The correction — I fixed the instance, not the class
The `end_coroutine` fix above was **too narrow**, and the giveaway was again an
impossible output: the listing showed
```
if builtin80(TCT206) == 0 … == 1 … == 2 … == 3 … == 4 … == 5
```
a six-way switch on a built-in that returns only **1 or 0**. Reading
`builtin80`'s body (`0x82268460`) settles that it is not a predicate at all — it
allocates a 20-byte object, stamps a vtable `0x820A8CB0`, a magic `0xAB0311BA`
and the unit's live object into it, pushes it onto a queue via the same helper
`push.i` uses, and returns 1, or 0 when the unit is absent. **It is a command.**
Disassembling the site explains it:
```
01B698 call builtin80(TCT206)
01B6A4 set.i global[76] = 0
01B6B0 jmp -> 0x1B738
01B6B8 jmp -> 0x1B738
01B6C0 cmp.i … <- reached ONLY by a branch from elsewhere
```
Two unconditional jumps sit between the call and the compare. **`op12` is
unconditional, so the next instruction is never reached by fall-through** — and
the tracker walked straight through it, exactly as it had walked through
`end_coroutine`. One is a thread boundary and the other a block boundary, but
they are the same defect: a linear walk cannot carry state across a point where
control does not flow.
| A/B over all 28 stages, 7563 sites | |
|---|---|
| sites whose operands change once `jmp` also resets | **889 — 11.75 %** |
| LHS unresolved, before → after | 34 (0.45 %) → **756 (10.00 %)** |
So the earlier "0.0 % unresolved" was not a strong result, it was a **missing
check**: the walk always had *some* value to report, and reporting it was the
bug. 10 % is the honest figure, and the remaining 90 % is now trustworthy for a
reason — the state reaching those sites really does flow there.
🟡 **Recovering the 756 needs real dataflow.** Each is a block entered only by a
branch, so its state is the *join* over its actual predecessors — a fixpoint over
the CFG, not a linear pass. The branch targets are all known (`[phase+232] +
word@+4`), so the CFG is available; the analysis is not written.
**Method note worth keeping:** when the same defect appears twice, fix the class.
Patching `end_coroutine` alone left 22× more bad sites in place than it removed,
and only another impossible-looking output exposed them.

View File

@@ -76,9 +76,16 @@ A 40× separation, and the additions sit exactly on the positive class.
raw number becoming a unit name:
```
- 0x01B6C0 if builtin80(0x8B) == 0 -> + 0x01B6C0 if builtin80(TCT206) == 0
- 0x01B6C0 if builtin80(1, 117) == 0 -> + 0x01B6C0 if builtin80(TCT206) == 0
```
⚠️ **That example was itself a bogus site** — see
[isl-conditions](isl-conditions.md#-the-correction--i-fixed-the-instance-not-the-class).
`0x1B6C0` is reached only by a branch, so attributing its comparison to
`builtin80` was wrong, and `builtin80` is a command rather than a predicate. The
UNIT_ARG result is unaffected — it was derived by reading implementations, not
from this listing — but the illustration was picked from bad output.
## 🟡 Not settled
* **The 24 are still unnamed.** Knowing an argument is a unit is not knowing what