re: recover ISL conditions by CFG dataflow instead of a linear walk

The linear walk's 10% unknown was a floor imposed by the method: a block entered only
by a branch has a well-defined state, just not one a straight-line pass can see.
tools/re-capture/isl_cfg.py replaces it with a worklist fixpoint that joins each
block's state over its ACTUAL predecessors -- a value survives only if every
predecessor agrees.

Over all 28 stages:
  instructions reached by the CFG          85.0%
  condition sites, unknown LHS             756 (10.00%) -> 402 (5.32%)
  of those, never reached at all           389
  joined away (predecessors disagree)       13
  both resolve but DISAGREE                161   <- linear walk was wrong here

Those 161 are on top of the 889 the previous jmp fix caught.

Two zero-results on the way, both my own bug, both caught because the number looked
wrong rather than because a test failed:

  * The first CFG run reached only 36% of instructions and made things WORSE (35%
    unknown).  Cause: the phase bases reach almost nothing.  Most routines are
    COROUTINES the engine starts from its trigger queue, with no static predecessor,
    so every start_coroutine target has to be seeded as an entry.
  * That seeding then found ZERO entries in a file with 216 start_coroutine calls,
    because the target is staged in TWO steps -- special[0] = imm, then
    local[0] = special[0] -- and I matched only the direct-immediate form.

Reachability went 36% -> 64% -> 85% as each was fixed.

The 389 still unreached are an honest limit rather than a gap: nothing in the bytecode
starts them; they are entered from the trigger queue at phase+272, by data rather than
code, so no purely static analysis reaches them.

isl_report.py conditions now uses isl_cfg; calls and phase-ends regenerate
byte-identical.  Stage 02 unknowns drop from 71 to 25.
This commit is contained in:
Sylpheed RE agent
2026-08-27 06:02:37 +00:00
parent b42cd7183c
commit 29eda81ede
5 changed files with 371 additions and 132 deletions

View File

@@ -1442,9 +1442,18 @@ premise was wrong.**
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
~~🟡 Recovering the 756 needs a real dataflow join over each block's actual
predecessors (a CFG fixpoint) — the analysis is not written.~~
**(2026-08-27) WRITTEN — `tools/re-capture/isl_cfg.py`.** Worklist fixpoint,
join over actual predecessors. **85.0 %** of instructions reached; unknown LHS
**756 (10.00 %) → 402 (5.32 %)**, of which **389 are never reached** and only
**13** are genuine join-aways. It also found **161 more sites where the linear
walk gave a confident WRONG answer**. ⚠️ Two of my own zero-results on the way:
the phase bases reach only 36 % (most routines are coroutines with no static
predecessor, so every `start_coroutine` target must be seeded), and that seeding
first found **0 entries in a file with 216** because the target is staged in TWO
steps (`special[0]=imm` then `local[0]=special[0]`). 🟡 The 389 are a real limit:
they are started from the **trigger queue at `phase+272`** — by data, not code. ▶️ **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]`,

View File

@@ -6,37 +6,41 @@ The deque ops are an expression stack: `push.i` saves the comparand,
the right-hand side is evaluated (its result lands in `special[0]`),
`pop.i` restores the comparand into `special[1]`, then `cmp.i` compares.
Operands come from a CFG dataflow fixpoint (`isl_cfg.py`), joining each
block over its ACTUAL predecessors — not from a linear walk.
965 condition sites; phase bases 0xe4 0x14aa8 0x24b4c
## most-tested predicates
unit_state 255
hp_pct_test 167
unit_state 248
hp_pct_test 165
dist_lt 92
unit_alive 71
unit_alive 62
unit_relation 52
builtin103 39
builtin105 38
read_freg 10
builtin103 35
random 26
unit_hp_pct 9
read_freg 9
builtin7 9
builtin99 1
## phase 1 — 435 sites
0x002E48 if builtin103() != 1 -> 0x322C
0x0032F4 if unit_alive(TCN105) != 1 -> 0x3388
0x0044A4 if unit_alive(TCN105) != 1 -> 0x4538
0x002E48 if <unknown: no static entry> != <unknown> -> 0x322C
0x0032F4 if <unknown: no static entry> != <unknown> -> 0x3388
0x0044A4 if <unknown: no static entry> != <unknown> -> 0x4538
0x004D70 if unit_hp_pct(TCN001, Character_Player_Test) != 0 -> 0x51FC
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
0x005110 if random(3) == 0 -> 0x4E68
0x005124 if random(3) == 1 -> 0x4F10
0x005138 if random(3) == 2 -> 0x4FB8
0x00514C if random(3) == 3 -> 0x5060
0x00523C if hp_pct_test(TCN004, 0) != 1 -> 0x5840
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
0x00572C if random(5) == 0 -> 0x5334
0x005740 if random(5) == 1 -> 0x53DC
0x005754 if random(5) == 2 -> 0x5484
0x005768 if random(5) == 3 -> 0x552C
0x00577C if random(5) == 4 -> 0x55D4
0x005790 if random(5) == 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
@@ -270,21 +274,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: 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
0x0105C4 if global[20] == 28 -> 0xFB1C
0x0105D8 if global[20] == 29 -> 0xFBD0
0x0105EC if global[20] == 30 -> 0xFC84
0x010600 if global[20] == 31 -> 0xFD38
0x010614 if global[20] == 32 -> 0xFDEC
0x010628 if global[20] == 33 -> 0xFEA0
0x01063C if global[20] == 34 -> 0xFF54
0x010650 if global[20] == 35 -> 0x10008
0x010664 if global[20] == 36 -> 0x100BC
0x010678 if global[20] == 37 -> 0x10170
0x01068C if global[20] == 38 -> 0x10224
0x0106A0 if global[20] == 39 -> 0x102D8
0x0106B4 if global[20] == 40 -> 0x1038C
0x0106C8 if global[20] == 41 -> 0x10440
0x0106DC if global[20] == 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
@@ -404,31 +408,31 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x012F1C if unit_state(ADN131) != 2 -> 0x12FAC
0x012F30 if global[36] != 0 -> 0x12FAC
0x012F68 if builtin105(ADN131) != 1 -> 0x12FAC
0x012FF0 if unit_state(ADN132, global[12], 1) != 2 -> 0x13080
0x012FF0 if unit_state(ADN132) != 2 -> 0x13080
0x013004 if global[40] != 0 -> 0x13080
0x01303C if builtin105(ADN132) != 1 -> 0x13080
0x0130C4 if unit_state(ADN133, global[12], 1) != 2 -> 0x13154
0x0130C4 if unit_state(ADN133) != 2 -> 0x13154
0x0130D8 if global[44] != 0 -> 0x13154
0x013110 if builtin105(ADN133) != 1 -> 0x13154
0x013198 if unit_state(ADN134, global[12], 1) != 2 -> 0x13228
0x013198 if unit_state(ADN134) != 2 -> 0x13228
0x0131AC if global[48] != 0 -> 0x13228
0x0131E4 if builtin105(ADN134) != 1 -> 0x13228
0x01326C if unit_state(ADN135, global[12], 1) != 2 -> 0x132FC
0x01326C if unit_state(ADN135) != 2 -> 0x132FC
0x013280 if global[52] != 0 -> 0x132FC
0x0132B8 if builtin105(ADN135) != 1 -> 0x132FC
0x013340 if unit_state(ADN136, global[12], 1) != 2 -> 0x133D0
0x013340 if unit_state(ADN136) != 2 -> 0x133D0
0x013354 if global[56] != 0 -> 0x133D0
0x01338C if builtin105(ADN136) != 1 -> 0x133D0
0x013414 if unit_state(ADN137, global[12], 1) != 2 -> 0x134A4
0x013414 if unit_state(ADN137) != 2 -> 0x134A4
0x013428 if global[60] != 0 -> 0x134A4
0x013460 if builtin105(ADN137) != 1 -> 0x134A4
0x0134E8 if unit_state(ADN138, global[12], 1) != 2 -> 0x13578
0x0134E8 if unit_state(ADN138) != 2 -> 0x13578
0x0134FC if global[64] != 0 -> 0x13578
0x013534 if builtin105(ADN138) != 1 -> 0x13578
0x0135BC if unit_state(ADN139, global[12], 1) != 2 -> 0x1364C
0x0135BC if unit_state(ADN139) != 2 -> 0x1364C
0x0135D0 if global[68] != 0 -> 0x1364C
0x013608 if builtin105(ADN139) != 1 -> 0x1364C
0x013690 if unit_state(ADN140, global[12], 1) != 2 -> 0x13720
0x013690 if unit_state(ADN140) != 2 -> 0x13720
0x0136A4 if global[72] != 0 -> 0x13720
0x0136DC if builtin105(ADN140) != 1 -> 0x13720
0x013724 if global[12] < 6 -> 0x14264
@@ -452,28 +456,28 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x014340 if global[16] >= 4 -> 0x143F4
0x0143F4 if global[12] < 3 -> 0x144BC
0x014408 if global[16] >= 3 -> 0x144BC
0x014504 if builtin103(global[12]) != 0 -> 0x14524
0x014504 if builtin103() != 0 -> 0x14524
0x014524 if global[28] != 1 -> 0x145E4
0x014628 if unit_state(ADS151) != 1 -> 0x14694
0x014680 if unit_state(TCS151) == 1 -> 0x146A0
0x014744 if dist_lt(TCN001, ADS151, 8000) == 1 -> 0x1481C
## phase 2 — 302 sites
0x018580 if builtin103() != 1 -> 0x186E8
0x018C30 if unit_alive(TCN208) != 1 -> 0x18C98
0x018CBC if unit_alive(TCN207) != 1 -> 0x18D24
0x018DB8 if hp_pct_test(ADN204, 0) != 1 -> 0x18E4C
0x018FFC if hp_pct_test(ADN208, 0) != 1 -> 0x19090
0x019124 if builtin103() != 1 -> 0x1915C
0x018580 if <unknown: no static entry> != <unknown> -> 0x186E8
0x018C30 if <unknown: no static entry> != <unknown> -> 0x18C98
0x018CBC if <unknown: no static entry> != <unknown> -> 0x18D24
0x018DB8 if <unknown: no static entry> != <unknown> -> 0x18E4C
0x018FFC if <unknown: no static entry> != <unknown> -> 0x19090
0x019124 if <unknown: no static entry> != <unknown> -> 0x1915C
0x0191CC if unit_hp_pct(TCN001, Character_Player_Test) != 0 -> 0x19658
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
0x01956C if random(3) == 0 -> 0x192C4
0x019580 if random(3) == 1 -> 0x1936C
0x019594 if random(3) == 2 -> 0x19414
0x0195A8 if random(3) == 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
0x019A8C if read_freg(0, 1) <= 240 -> 0x1A1E4
0x019A8C if <unknown: no static entry> <= 240 -> 0x1A1E4
0x019AE0 if hp_pct_test(ADN201, 0) != 1 -> 0x1A1E4
0x019B34 if hp_pct_test(ADN202, 0) != 1 -> 0x1A1E4
0x019B88 if hp_pct_test(ADN203, 0) != 1 -> 0x1A1E4
@@ -499,18 +503,18 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x01A1E4 if global[4] == 0 -> 0x1AC5C
0x01A2B0 if global[4] != 1 -> 0x1A864
0x01A2F4 if unit_alive(ADN201, 0) != 1 -> 0x1A32C
0x01A350 if unit_alive(ADN202, global[104]) != 1 -> 0x1A388
0x01A3AC if unit_alive(ADN207, global[104]) != 1 -> 0x1A3E4
0x01A408 if unit_alive(ADN223, global[104]) != 1 -> 0x1A440
0x01A464 if unit_alive(ADN224, global[104]) != 1 -> 0x1A49C
0x01A4C0 if unit_alive(ADN225, global[104]) != 1 -> 0x1A4F8
0x01A51C if unit_alive(ADN226, global[104]) != 1 -> 0x1A554
0x01A578 if unit_alive(ADN227, global[104]) != 1 -> 0x1A5B0
0x01A5D4 if unit_alive(ADN228, global[104]) != 1 -> 0x1A60C
0x01A630 if unit_alive(ADN229, global[104]) != 1 -> 0x1A668
0x01A68C if unit_alive(ADN230, global[104]) != 1 -> 0x1A6C4
0x01A6E8 if unit_alive(ADN231, global[104]) != 1 -> 0x1A720
0x01A744 if unit_alive(ADN232, global[104]) != 1 -> 0x1A77C
0x01A350 if unit_alive(ADN202) != 1 -> 0x1A388
0x01A3AC if unit_alive(ADN207) != 1 -> 0x1A3E4
0x01A408 if unit_alive(ADN223) != 1 -> 0x1A440
0x01A464 if unit_alive(ADN224) != 1 -> 0x1A49C
0x01A4C0 if unit_alive(ADN225) != 1 -> 0x1A4F8
0x01A51C if unit_alive(ADN226) != 1 -> 0x1A554
0x01A578 if unit_alive(ADN227) != 1 -> 0x1A5B0
0x01A5D4 if unit_alive(ADN228) != 1 -> 0x1A60C
0x01A630 if unit_alive(ADN229) != 1 -> 0x1A668
0x01A68C if unit_alive(ADN230) != 1 -> 0x1A6C4
0x01A6E8 if unit_alive(ADN231) != 1 -> 0x1A720
0x01A744 if unit_alive(ADN232) != 1 -> 0x1A77C
0x01A77C if global[104] <= 1 -> 0x1A844
0x01A924 if hp_pct_test(TCT206, 89.9) != 0 -> 0x1AA38
0x01AA38 if global[104] != 0 -> 0x1AAEC
@@ -536,12 +540,12 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x01B554 if dist_lt(TCT206, ADN231, 20000) == 1 -> 0x1B598
0x01B5E0 if hp_pct_test(ADN232, 0) == 1 -> 0x1B680
0x01B66C if dist_lt(TCT206, ADN232, 20000) == 1 -> 0x1B6B0
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
0x01B6C0 if global[76] == 0 -> 0x1AC74
0x01B6D4 if global[76] == 1 -> 0x1B140
0x01B6E8 if global[76] == 2 -> 0x1B258
0x01B6FC if global[76] == 3 -> 0x1B370
0x01B710 if global[76] == 4 -> 0x1B488
0x01B724 if global[76] == 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
@@ -563,12 +567,12 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x01C090 if dist_lt(TCN207, ADN231, 20000) == 1 -> 0x1C0D4
0x01C11C if hp_pct_test(ADN232, 0) == 1 -> 0x1C1BC
0x01C1A8 if dist_lt(TCN207, ADN232, 20000) == 1 -> 0x1C1EC
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
0x01C1FC if global[80] == 0 -> 0x1B7B0
0x01C210 if global[80] == 1 -> 0x1BC7C
0x01C224 if global[80] == 2 -> 0x1BD94
0x01C238 if global[80] == 3 -> 0x1BEAC
0x01C24C if global[80] == 4 -> 0x1BFC4
0x01C260 if global[80] == 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
@@ -590,12 +594,12 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x01CBCC if dist_lt(TCN208, ADN231, 20000) == 1 -> 0x1CC10
0x01CC58 if hp_pct_test(ADN232, 0) == 1 -> 0x1CCF8
0x01CCE4 if dist_lt(TCN208, ADN232, 20000) == 1 -> 0x1CD28
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
0x01CD38 if global[84] == 0 -> 0x1C2EC
0x01CD4C if global[84] == 1 -> 0x1C7B8
0x01CD60 if global[84] == 2 -> 0x1C8D0
0x01CD74 if global[84] == 3 -> 0x1C9E8
0x01CD88 if global[84] == 4 -> 0x1CB00
0x01CD9C if global[84] == 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
@@ -611,11 +615,11 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x01D9EC if dist_lt(ADN201, TCN208, 20000) == 1 -> 0x1DA30
0x01DAA8 if builtin7(ADN201, 1, Route_ADN201_p2S, 4294967295, 500) != 1 -> 0x1DB48
0x01DBC0 if dist_lt(ADN201, TCT206, 20000) == 1 -> 0x1DC04
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
0x01DC1C if global[88] == 0 -> 0x1D258
0x01DC30 if global[88] == 1 -> 0x1D5E8
0x01DC44 if global[88] == 2 -> 0x1D810
0x01DC58 if global[88] == 3 -> 0x1DA38
0x01DC6C if global[88] == 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
@@ -636,11 +640,11 @@ the right-hand side is evaluated (its result lands in `special[0]`),
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 <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
0x01E9E8 if global[96] == 0 -> 0x1DD80
0x01E9FC if global[96] == 1 -> 0x1E1D4
0x01EA10 if global[96] == 2 -> 0x1E49C
0x01EA24 if global[96] == 3 -> 0x1E764
0x01EA38 if global[96] == 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
@@ -763,24 +767,24 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x02492C if dist_lt(TCT206, ADN202, 10000) != 1 -> 0x249EC
## phase 3 — 228 sites
0x028B98 if builtin103() != 1 -> 0x28E20
0x029C78 if unit_alive(TCN002) != 1 -> 0x29D04
0x02A4D8 if unit_alive(TCN002) != 1 -> 0x2A60C
0x02A630 if unit_alive(TCN003) != 1 -> 0x2A764
0x02B0D8 if unit_alive(TCN002) != 1 -> 0x2B20C
0x02B230 if unit_alive(TCN003) != 1 -> 0x2B310
0x028B98 if <unknown: no static entry> != <unknown> -> 0x28E20
0x029C78 if <unknown: no static entry> != <unknown> -> 0x29D04
0x02A4D8 if <unknown: no static entry> != <unknown> -> 0x2A60C
0x02A630 if <unknown: no static entry> != <unknown> -> 0x2A764
0x02B0D8 if <unknown: no static entry> != <unknown> -> 0x2B20C
0x02B230 if <unknown: no static entry> != <unknown> -> 0x2B310
0x02B4F8 if unit_hp_pct(TCN001, Character_Player_Test) != 0 -> 0x2B984
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
0x02B898 if random(3) == 0 -> 0x2B5F0
0x02B8AC if random(3) == 1 -> 0x2B698
0x02B8C0 if random(3) == 2 -> 0x2B740
0x02B8D4 if random(3) == 3 -> 0x2B7E8
0x02B9C4 if hp_pct_test(TCN004, 0) != 1 -> 0x2BFC8
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
0x02BEB4 if random(5) == 0 -> 0x2BABC
0x02BEC8 if random(5) == 1 -> 0x2BB64
0x02BEDC if random(5) == 2 -> 0x2BC0C
0x02BEF0 if random(5) == 3 -> 0x2BCB4
0x02BF04 if random(5) == 4 -> 0x2BD5C
0x02BF18 if random(5) == 5 -> 0x2BE04
0x02BFC8 if global[112] < 4 -> 0x2C1F8
0x02C240 if read_freg(0) <= 300 -> 0x2CF8C
0x02C294 if hp_pct_test(ADT301, 0) != 1 -> 0x2CF8C
@@ -839,12 +843,12 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x02F5BC if global[124] != 0 -> 0x2F664
0x02F5F4 if unit_alive(ADT306) != 1 -> 0x2F664
0x02F644 if unit_relation(TCN003, ADT306) != 1 -> 0x2F664
0x02F6A4 if hp_pct_test(ADT306, 0, 1) != 1 -> 0x2F82C
0x02F6A4 if hp_pct_test(ADT306, 0) != 1 -> 0x2F82C
0x02F6B8 if global[120] != 0 -> 0x2F780
0x02F6CC if global[124] != 1 -> 0x2F780
0x02F830 if global[108] != 1 -> 0x2F9FC
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
0x02F9C8 if random(1) == 0 -> 0x2F870
0x02F9DC if random(1) == 1 -> 0x2F918
0x02FA44 if 8 < 1 -> 0x2FBC8
0x02FC10 if 8 < 3 -> 0x2FCF4
0x02FD3C if 8 < 4 -> 0x2FE20
@@ -964,7 +968,7 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x034110 if global[16] >= 2 -> 0x341C4
0x0341C4 if global[12] < 1 -> 0x3428C
0x0341D8 if global[16] >= 1 -> 0x3428C
0x0342EC if unit_state(ADT301, global[12]) == 1 -> 0x34358
0x0342EC if unit_state(ADT301) == 1 -> 0x34358
0x034344 if unit_state(ADT302) != 1 -> 0x345FC
0x03439C if unit_state(TCN000) == 1 -> 0x343BC
0x034400 if unit_state(ADT301) == 1 -> 0x34478
@@ -974,20 +978,20 @@ the right-hand side is evaluated (its result lands in `special[0]`),
0x03460C if global[20] == 8 -> 0x34634
0x034620 if global[20] != 9 -> 0x34640
0x034640 if global[20] != 0 -> 0x346B8
0x034698 if unit_state(ADT301) == 1 -> 0x346B8
0x034698 if unit_state(ADT301, 1) == 1 -> 0x346B8
0x0346B8 if global[20] != 1 -> 0x34730
0x034710 if unit_state(ADT302) == 1 -> 0x34730
0x034710 if <unknown: no static entry> == 1 -> 0x34730
0x034730 if global[20] != 2 -> 0x347A8
0x034788 if unit_state(ADT303) == 1 -> 0x347A8
0x034788 if <unknown: no static entry> == 1 -> 0x347A8
0x0347A8 if global[20] != 3 -> 0x34820
0x034800 if unit_state(ADT304) == 1 -> 0x34820
0x034800 if <unknown: no static entry> == 1 -> 0x34820
0x034820 if global[20] != 4 -> 0x34898
0x034878 if unit_state(ADT305) == 1 -> 0x34898
0x034878 if <unknown: no static entry> == 1 -> 0x34898
0x034898 if global[20] != 5 -> 0x34910
0x0348F0 if unit_state(ADT306) == 1 -> 0x34910
0x0348F0 if <unknown: no static entry> == 1 -> 0x34910
0x034910 if global[20] != 6 -> 0x34988
0x034968 if unit_state(ADT307) == 1 -> 0x34988
0x034968 if <unknown: no static entry> == 1 -> 0x34988
0x034988 if global[20] != 7 -> 0x34A00
0x0349E0 if unit_state(ADT308) == 1 -> 0x34A00
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
0x0349E0 if <unknown: no static entry> == 1 -> 0x34A00
0x034A90 if <unknown: no static entry> == <unknown> -> 0x34A30
0x034AA4 if <unknown: no static entry> == <unknown> -> 0x34A5C

View File

@@ -47,7 +47,7 @@ the stack, then reports each compare with its branch:
| | all 28 stages |
|---|---|
| condition sites | **7 563** |
| **LHS honestly unresolved** | **756 — 10.0 %** |
| **LHS honestly unresolved** | **402 — 5.3 %** (CFG dataflow; the linear walk left 756) |
| RHS is a plain number | 7 544 — 99.7 % |
🔴 **The first version of this table claimed 0.0 % unresolved. That was wrong**
@@ -182,4 +182,47 @@ 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.
and only another impossible-looking output exposed them.
## ✅ Replaced by a CFG dataflow fixpoint — `isl_cfg.py`
The linear walk's honest 10 % unknown was a floor imposed by the method, not by
the data: a block entered only by a branch has *a* well-defined state, just not
one a straight-line pass can see. So the walk is gone, replaced by a worklist
fixpoint that joins each block's state over its **actual predecessors** — a value
survives only if every predecessor agrees.
| over all 28 stages | linear walk | CFG dataflow |
|---|---|---|
| instructions reached | (all, but with stale state) | **85.0 %** |
| condition sites with an unknown LHS | 756 — 10.00 % | **402 — 5.32 %** |
| of those, never reached at all | — | 389 |
| joined away (predecessors genuinely disagree) | — | **13** |
| **sites where both resolve but DISAGREE** | — | **161** |
Those 161 are 161 more places the linear walk reported a confident wrong answer,
on top of the 889 the `jmp` fix caught.
### ⚠️ Two zero-results that were both my bug
The first CFG run reached only **36 %** of instructions and made things *worse*
— 35 % unknown against the walk's 10 %. Two causes, and each surfaced as a
suspiciously round zero:
1. **The phase bases reach almost nothing.** Most routines are **coroutines** the
engine starts from its trigger queue, so they have no static predecessor at
all. They must be seeded from every `start_coroutine` target.
2. **The seeding found ZERO entries in a file with 216 `start_coroutine` calls.**
The target is staged in *two* steps — `special[0] = imm`, then
`local[0] = special[0]` — and I matched only the direct-immediate form.
Reachability went 36 % → 64 % → **85 %** as each was fixed. The lesson is the one
this corpus keeps re-teaching: *a count that does not move when it should is the
bug reporting itself.* Both times I checked because the number looked wrong, not
because a test failed.
### 🟡 The 389 that remain are a real limit, not a gap
Nothing in the bytecode starts them. They are entered from the **trigger queue at
`phase+272`** — by data, not by code — so no purely static analysis reaches them.
Resolving those needs the trigger table's contents, which is a separate question.