diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index 23592232..f586a361 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -1486,6 +1486,15 @@ premise was wrong.** phase 3's requires `ADT301`/`ADT302`, and `read_freg(0)` gates at 210/300/1200. 🟡 Dominance gives NECESSARY not sufficient conditions. 🟡 2 of 15 exits are reachable from NO static entry — consistent with the trigger queue at `phase+272`. + ✅ **(2026-08-27) EXTENDED TO ALL 28 STAGES** — `data/isl-phase-guards-all.txt` + (`isl_report.py phase-guards`). **177 exits, only 5 (2.8 %) unreachable**; + CFG reach 69.5 % (S26) to 95.8 % (S25), ~4 conditions per exit. 🔑 **Independent + cross-check, 6/6:** all six TUTORIAL stages (S18–S23) have exactly one exit with + exactly one dominating condition, `builtin104() != 1` — and `isl-builtins.md` + derived built-in 104 from usage alone as "S18–S23 only, a textbook poll loop". + Two unrelated methods agree. S16 (the compiled-C++-script outlier) resolves too: + `read_freg(0) < 600`, `player_gauge0/1_test`, and two `builtin141` calls differing + only in one argument (`0` vs `-4000`) — a position/zone shape, unread so unnamed. 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`. diff --git a/docs/re/data/isl-phase-guards-all.txt b/docs/re/data/isl-phase-guards-all.txt new file mode 100644 index 00000000..a0498b67 --- /dev/null +++ b/docs/re/data/isl-phase-guards-all.txt @@ -0,0 +1,1452 @@ +# Stage01.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 8256 of 9879 instructions (83.6%). + +## phase 1 — END_PHASE at 0x002B6C: 2 necessary condition(s) + 0x002870 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002AC0 random(2) == 0 + +## phase 1 — END_PHASE at 0x003178: 7 necessary condition(s) + 0x002870 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002BC4 hp_pct_test(ADT101, 0) != 1 + 0x002C18 hp_pct_test(ADT102, 0) != 1 + 0x002C6C hp_pct_test(ADT103, 0) != 1 + 0x002CC0 hp_pct_test(ADT104, 0) != 1 + 0x002D98 global[0] != 9 + 0x00302C global[4] == 0 + +## phase 1 — END_PHASE at 0x0033C8: 3 necessary condition(s) + 0x002870 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002BC4 hp_pct_test(ADT101, 0) != 1 + 0x0031D8 read_freg(0) < 600 + +## phase 1 — FORCE_END_PHASE at 0x00E0B4: 2 necessary condition(s) + 0x00DFD4 builtin103() == 1 + 0x00E034 hp_pct_test(ADS129, 0) != 1 + +## phase 2 — END_PHASE at 0x011B10: 2 necessary condition(s) + 0x011814 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x011A64 random(2) == 0 + +## phase 2 — END_PHASE at 0x012714: 10 necessary condition(s) + 0x011814 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x011B70 read_freg(0) < 70 + 0x011BC4 hp_pct_test(ADT201, 0) != 1 + 0x011C18 hp_pct_test(ADT202, 0) != 1 + 0x011C6C hp_pct_test(ADT203, 0) != 1 + 0x011CC0 hp_pct_test(ADT204, 0) != 1 + 0x011D14 hp_pct_test(ADT205, 0) != 1 + 0x011E38 hp_pct_test(ADS221, 0) != 1 + 0x012508 builtin103() != 1 + 0x0125C8 global[4] == 0 + +## phase 2 — END_PHASE at 0x012964: 3 necessary condition(s) + 0x011814 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x011B70 read_freg(0) < 70 + 0x012774 read_freg(0) < 600 + +## phase 2 — FORCE_END_PHASE at 0x01B828: 4 necessary condition(s) + 0x01B4FC builtin103() == 1 + 0x01B55C hp_pct_test(ADT205, 0) != 1 + 0x01B5A0 unit_alive(ADT205) != 1 + 0x01B6F8 unit_alive(ADT205) != 1 + +------------------------------------------------------------------------ + +# Stage02.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 15670 of 18739 instructions (83.6%). + +## phase 1 — END_PHASE at 0x0051E4: 2 necessary condition(s) + 0x004D70 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x005110 random(3) == 0 + +## phase 1 — END_PHASE at 0x005828: 3 necessary condition(s) + 0x004D70 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00523C hp_pct_test(TCN004, 0) != 1 + 0x00572C random(5) == 0 + +## phase 1 — END_PHASE at 0x006010: 7 necessary condition(s) + 0x004D70 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00523C hp_pct_test(TCN004, 0) != 1 + 0x005888 read_freg(0) <= 210 + 0x0058DC hp_pct_test(ADT102, 0) != 1 + 0x005930 hp_pct_test(ADT107, 0) != 1 + 0x005984 hp_pct_test(ADT113, 0) != 1 + 0x005B3C hp_pct_test(ADN101, 0) != 1 + +## phase 1 — END_PHASE at 0x006260: 4 necessary condition(s) + 0x004D70 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00523C hp_pct_test(TCN004, 0) != 1 + 0x005888 read_freg(0) <= 210 + 0x006070 read_freg(0) < 1200 + +## phase 1 — FORCE_END_PHASE at 0x01482C: UNREACHABLE from any static entry + (started from the trigger queue at `phase+272`, by data not code) + +## phase 2 — END_PHASE at 0x019640: 2 necessary condition(s) + 0x0191CC unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x01956C random(3) == 0 + +## phase 2 — END_PHASE at 0x019934: 2 necessary condition(s) + 0x0191CC unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x019698 hp_pct_test(TCT206, 0) != 1 + +## phase 2 — END_PHASE at 0x01AC44: 9 necessary condition(s) + 0x0191CC unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x019698 hp_pct_test(TCT206, 0) != 1 + 0x0199C8 builtin7(TCT206, 1, Route_TCT206_p2S, 4294967295, 500) == 1 + 0x019A8C <= 240 + 0x01A1E4 global[4] == 0 + 0x01A2B0 global[4] != 1 + 0x01A924 hp_pct_test(TCT206, 89.9) != 0 + 0x01AA38 global[104] != 0 + 0x01AAF8 global[4] == 0 + +## phase 2 — FORCE_END_PHASE at 0x0249F0: 2 necessary condition(s) + 0x0247E4 hp_pct_test(ADN202, 0) != 1 + 0x024848 unit_state(TCT206) != 1 + +## phase 3 — END_PHASE at 0x02B96C: 2 necessary condition(s) + 0x02B4F8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x02B898 random(3) == 0 + +## phase 3 — END_PHASE at 0x02BFB0: 3 necessary condition(s) + 0x02B4F8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x02B9C4 hp_pct_test(TCN004, 0) != 1 + 0x02BEB4 random(5) == 0 + +## phase 3 — END_PHASE at 0x02C1E0: 3 necessary condition(s) + 0x02B4F8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x02B9C4 hp_pct_test(TCN004, 0) != 1 + 0x02BFC8 global[112] < 4 + +## phase 3 — END_PHASE at 0x02CF74: 16 necessary condition(s) + 0x02B4F8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x02B9C4 hp_pct_test(TCN004, 0) != 1 + 0x02BFC8 global[112] < 4 + 0x02C240 read_freg(0) <= 300 + 0x02C294 hp_pct_test(ADT301, 0) != 1 + 0x02C2E8 hp_pct_test(ADT302, 0) != 1 + 0x02C33C hp_pct_test(ADT303, 0) != 1 + 0x02C390 hp_pct_test(ADT304, 0) != 1 + 0x02C3E4 hp_pct_test(ADT305, 0) != 1 + 0x02C438 hp_pct_test(ADT306, 0) != 1 + 0x02C48C hp_pct_test(ADT307, 0) != 1 + 0x02C4E0 hp_pct_test(ADT308, 0) != 1 + 0x02C5C4 global[112] != 0 + 0x02CC0C global[112] != 0 + 0x02CDC8 global[4] == 0 + 0x02CE9C global[112] != 0 + +## phase 3 — END_PHASE at 0x02D1DC: 5 necessary condition(s) + 0x02B4F8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x02B9C4 hp_pct_test(TCN004, 0) != 1 + 0x02BFC8 global[112] < 4 + 0x02C240 read_freg(0) <= 300 + 0x02CFD4 read_freg(0) < 1200 + +## phase 3 — FORCE_END_PHASE at 0x034A10: UNREACHABLE from any static entry + (started from the trigger queue at `phase+272`, by data not code) + +------------------------------------------------------------------------ + +# Stage03.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 8382 of 11105 instructions (75.5%). + +## phase 1 — END_PHASE at 0x003924: 2 necessary condition(s) + 0x0034B0 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x003850 random(3) == 0 + +## phase 1 — END_PHASE at 0x003F68: 3 necessary condition(s) + 0x0034B0 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00397C hp_pct_test(TCN004, 0) != 1 + 0x003E6C random(5) == 0 + +## phase 1 — END_PHASE at 0x004688: 12 necessary condition(s) + 0x0034B0 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00397C hp_pct_test(TCN004, 0) != 1 + 0x003FC8 read_freg(0) < 210 + 0x00401C hp_pct_test(ADT101, 0) != 1 + 0x004070 hp_pct_test(ADT102, 0) != 1 + 0x0040C4 hp_pct_test(ADT103, 0) != 1 + 0x004118 hp_pct_test(ADT104, 0) != 1 + 0x00416C hp_pct_test(ADT105, 0) != 1 + 0x0041C0 hp_pct_test(ADT106, 0) != 1 + 0x004214 hp_pct_test(ADT107, 0) != 1 + 0x0043D0 unit_state(TCN106, 0) != 1 + 0x00453C global[8] == 0 + +## phase 1 — END_PHASE at 0x0048D8: 4 necessary condition(s) + 0x0034B0 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00397C hp_pct_test(TCN004, 0) != 1 + 0x003FC8 read_freg(0) < 210 + 0x0046E8 read_freg(0) < 600 + +## phase 1 — FORCE_END_PHASE at 0x009FF4: 2 necessary condition(s) + 0x009E60 unit_state(ADT101) == 1 + 0x009EC4 unit_state(ADT101) != 1 + +## phase 2 — END_PHASE at 0x00E1B8: 2 necessary condition(s) + 0x00DD44 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00E0E4 random(3) == 0 + +## phase 2 — END_PHASE at 0x00E7FC: 3 necessary condition(s) + 0x00DD44 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00E210 hp_pct_test(TCN004, 0) != 1 + 0x00E700 random(5) == 0 + +## phase 2 — END_PHASE at 0x00EA04: 3 necessary condition(s) + 0x00DD44 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00E210 hp_pct_test(TCN004, 0) != 1 + 0x00E814 global[44] != 3 + +## phase 2 — END_PHASE at 0x00F5A8: 9 necessary condition(s) + 0x00DD44 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00E210 hp_pct_test(TCN004, 0) != 1 + 0x00E814 global[44] != 3 + 0x00EA28 global[56] != 0 + 0x00EB5C read_freg(0) < 420 + 0x00EFC0 global[8] == 0 + 0x00F098 global[8] != 2 + 0x00F1E4 != 1 + 0x00F450 global[60] != 1 + +## phase 2 — FORCE_END_PHASE at 0x014CF8: UNREACHABLE from any static entry + (started from the trigger queue at `phase+272`, by data not code) + +## phase 3 — END_PHASE at 0x019638: 2 necessary condition(s) + 0x0191C4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x019564 random(3) == 0 + +## phase 3 — END_PHASE at 0x019C7C: 3 necessary condition(s) + 0x0191C4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x019690 hp_pct_test(TCN004, 0) != 1 + 0x019B80 random(5) == 0 + +## phase 3 — END_PHASE at 0x019E84: 3 necessary condition(s) + 0x0191C4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x019690 hp_pct_test(TCN004, 0) != 1 + 0x019C94 global[64] != 4 + +## phase 3 — END_PHASE at 0x01A6AC: 8 necessary condition(s) + 0x0191C4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x019690 hp_pct_test(TCN004, 0) != 1 + 0x019C94 global[64] != 4 + 0x019E9C global[76] != 2 + 0x019F68 global[64] != 0 + 0x019FEC hp_pct_test(ADN301, 0) != 1 + 0x01A340 global[80] != 1 + 0x01A560 global[8] == 0 + +## phase 3 — END_PHASE at 0x01AC5C: 8 necessary condition(s) + 0x0191C4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x019690 hp_pct_test(TCN004, 0) != 1 + 0x019C94 global[64] != 4 + 0x019E9C global[76] != 2 + 0x01A70C read_freg(0) < 600 + 0x01A7E4 global[64] != 0 + 0x01A994 global[44] != 0 + 0x01AB10 global[8] == 0 + +## phase 3 — FORCE_END_PHASE at 0x01F510: 1 necessary condition(s) + 0x01F200 hp_pct_test(ADN301, 0) != 1 + +------------------------------------------------------------------------ + +# Stage04.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 3688 of 4377 instructions (84.3%). + +## phase 1 — END_PHASE at 0x002B3C: 2 necessary condition(s) + 0x002698 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002A38 random(3) == 0 + +## phase 1 — END_PHASE at 0x0031B0: 3 necessary condition(s) + 0x002698 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002B94 hp_pct_test(TCN004, 0) != 1 + 0x003084 random(5) == 0 + +## phase 1 — END_PHASE at 0x00379C: 8 necessary condition(s) + 0x002698 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002B94 hp_pct_test(TCN004, 0) != 1 + 0x003208 hp_pct_test(ADT101, 0) != 1 + 0x00325C hp_pct_test(ADT102, 0) != 1 + 0x0032B0 hp_pct_test(ADT103, 0) != 1 + 0x003304 hp_pct_test(ADT106, 0) != 1 + 0x003358 hp_pct_test(ADT107, 0) != 1 + 0x003478 read_freg(0, 0) >= 130 + +## phase 1 — END_PHASE at 0x003A1C: 4 necessary condition(s) + 0x002698 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002B94 hp_pct_test(TCN004, 0) != 1 + 0x003208 hp_pct_test(ADT101, 0) != 1 + 0x0037FC read_freg(0) < 600 + +## phase 1 — FORCE_END_PHASE at 0x0052A4: 1 necessary condition(s) + 0x0051E0 hp_pct_test(ADT106, 0) != 1 + +## phase 2 — END_PHASE at 0x008918: 2 necessary condition(s) + 0x008474 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x008814 random(3) == 0 + +## phase 2 — END_PHASE at 0x008F8C: 3 necessary condition(s) + 0x008474 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x008970 hp_pct_test(TCN004, 0) != 1 + 0x008E60 random(5) == 0 + +## phase 2 — END_PHASE at 0x009944: 8 necessary condition(s) + 0x008474 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x008970 hp_pct_test(TCN004, 0) != 1 + 0x008FA4 global[16] != 1 + 0x008FF8 hp_pct_test(ADT203, 0) != 1 + 0x009110 hp_pct_test(ADN201, 0) != 1 + 0x009464 global[20] != 1 + 0x009660 builtin105(ADT203) != 1 + 0x0097C8 global[4] == 0 + +## phase 2 — END_PHASE at 0x009BC4: 4 necessary condition(s) + 0x008474 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x008970 hp_pct_test(TCN004, 0) != 1 + 0x008FA4 global[16] != 1 + 0x0099A4 read_freg(0) < 600 + +## phase 2 — FORCE_END_PHASE at 0x00C9CC: 1 necessary condition(s) + 0x00C6BC hp_pct_test(ADN201, 0) != 1 + +------------------------------------------------------------------------ + +# Stage05.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 4316 of 5194 instructions (83.1%). + +## phase 1 — END_PHASE at 0x0037C0: 4 necessary condition(s) + 0x002D84 unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x002F48 read_freg(0) < 600 + 0x00305C unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0033D4 hp_pct_test(TCN004, 0) != 1 + +## phase 1 — END_PHASE at 0x003D94: 15 necessary condition(s) + 0x002D84 unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x002DD8 hp_pct_test(TCN004, 0) == 1 + 0x002E34 read_freg(0) < 600 + 0x0037D8 global[4] != 1 + 0x00382C hp_pct_test(ADT101, 0) != 1 + 0x003880 hp_pct_test(ADT102, 0) != 1 + 0x0038D4 hp_pct_test(ADT103, 0) != 1 + 0x003928 hp_pct_test(ADT104, 0) != 1 + 0x00397C hp_pct_test(ADT105, 0) != 1 + 0x0039D0 hp_pct_test(ADT106, 0) != 1 + 0x003A24 hp_pct_test(ADT107, 0) != 1 + 0x003A78 hp_pct_test(ADT108, 0) != 1 + 0x003ACC hp_pct_test(ADT109, 0) != 1 + 0x003B20 hp_pct_test(ADT110, 0) != 1 + 0x003B74 hp_pct_test(ADT111, 0) != 1 + +## phase 1 — FORCE_END_PHASE at 0x007538: 1 necessary condition(s) + 0x0071DC dist_lt(TCN004, TCN001, 20000) == 1 + +## phase 2 — END_PHASE at 0x00A088: 4 necessary condition(s) + 0x00964C unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x009828 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x009BA0 hp_pct_test(TCN004, 0) != 1 + 0x009F20 read_freg(0) < 600 + +## phase 2 — END_PHASE at 0x00A410: 8 necessary condition(s) + 0x00964C unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x0096A0 hp_pct_test(TCN004, 0) == 1 + 0x0096FC read_freg(0) < 600 + 0x00A0A0 global[12] < 4 + 0x00A0F4 hp_pct_test(ADT205, 0) != 1 + 0x00A148 hp_pct_test(ADT206, 0) != 1 + 0x00A19C hp_pct_test(ADT207, 0) != 1 + 0x00A1F0 hp_pct_test(ADT208, 0) != 1 + +## phase 2 — FORCE_END_PHASE at 0x00EEF4: 2 necessary condition(s) + 0x00ED64 hp_pct_test(ADS251a, 0) != 1 + 0x00EDC4 hp_pct_test(TCN004, 40) != 1 + +------------------------------------------------------------------------ + +# Stage06.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 8409 of 9514 instructions (88.4%). + +## phase 1 — END_PHASE at 0x003778: 2 necessary condition(s) + 0x0032D4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x003674 random(3) == 0 + +## phase 1 — END_PHASE at 0x003DF4: 3 necessary condition(s) + 0x0032D4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0037D8 hp_pct_test(TCN004, 0) != 1 + 0x003CC8 random(5) == 0 + +## phase 1 — END_PHASE at 0x00407C: 3 necessary condition(s) + 0x0032D4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0037D8 hp_pct_test(TCN004, 0) != 1 + 0x003E5C read_freg(0) < 600 + +## phase 1 — END_PHASE at 0x0043A8: 5 necessary condition(s) + 0x0032D4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0037D8 hp_pct_test(TCN004, 0) != 1 + 0x003E5C read_freg(0) < 600 + 0x00409C global[0] < 9 + 0x00422C global[4] != 1 + +## phase 1 — FORCE_END_PHASE at 0x008EFC: 2 necessary condition(s) + 0x008D6C hp_pct_test(ADS151b, 0) != 1 + 0x008DCC hp_pct_test(TCN004, 40) != 1 + +## phase 2 — END_PHASE at 0x00C5D4: 2 necessary condition(s) + 0x00C130 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00C4D0 random(3) == 0 + +## phase 2 — END_PHASE at 0x00CC50: 3 necessary condition(s) + 0x00C130 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00C634 hp_pct_test(TCN004, 0) != 1 + 0x00CB24 random(5) == 0 + +## phase 2 — END_PHASE at 0x00CED8: 3 necessary condition(s) + 0x00C130 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00C634 hp_pct_test(TCN004, 0) != 1 + 0x00CCB8 read_freg(0) < 600 + +## phase 2 — END_PHASE at 0x00D8A8: 16 necessary condition(s) + 0x00C130 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00C634 hp_pct_test(TCN004, 0) != 1 + 0x00CCB8 read_freg(0) < 600 + 0x00CF3C unit_state(ADT215) == 0 + 0x00CF94 unit_state(ADT217) != 0 + 0x00CFF0 hp_pct_test(ADT201, 0) != 1 + 0x00D044 hp_pct_test(ADT208, 0) != 1 + 0x00D098 hp_pct_test(ADT209, 0) != 1 + 0x00D0EC hp_pct_test(ADT210, 0) != 1 + 0x00D140 hp_pct_test(ADT211, 0) != 1 + 0x00D194 hp_pct_test(ADT213, 0) != 1 + 0x00D1E8 hp_pct_test(ADT215, 0) != 1 + 0x00D23C hp_pct_test(ADT217, 0) != 1 + 0x00D358 unit_state(TCN209, 0) != 1 + 0x00D618 squad_survival_pct(TCN205, 99.9) == 1 + 0x00D72C global[8] == 0 + +## phase 2 — FORCE_END_PHASE at 0x010E18: 1 necessary condition(s) + 0x010D54 hp_pct_test(TCN215, 0) != 1 + +## phase 3 — END_PHASE at 0x013FCC: 2 necessary condition(s) + 0x013B28 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x013EC8 random(3) == 0 + +## phase 3 — END_PHASE at 0x014640: 3 necessary condition(s) + 0x013B28 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x014024 hp_pct_test(TCN004, 0) != 1 + 0x014514 random(5) == 0 + +## phase 3 — END_PHASE at 0x014ECC: 7 necessary condition(s) + 0x013B28 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x014024 hp_pct_test(TCN004, 0) != 1 + 0x014698 hp_pct_test(ADT301, 0) != 1 + 0x0146EC hp_pct_test(ADN302, 0) != 1 + 0x0148A8 unit_state(TCN306, 0) != 1 + 0x0149F0 hp_pct_test(ADT301, 0) != 1 + 0x014D50 global[8] == 0 + +## phase 3 — END_PHASE at 0x01514C: 4 necessary condition(s) + 0x013B28 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x014024 hp_pct_test(TCN004, 0) != 1 + 0x014698 hp_pct_test(ADT301, 0) != 1 + 0x014F2C read_freg(0) < 1200 + +## phase 3 — FORCE_END_PHASE at 0x01B31C: 3 necessary condition(s) + 0x01B0E8 unit_state(ADN321) != 1 + 0x01B140 unit_state(TCN001) == 1 + 0x01B1B8 dist_lt(ADN321, TCN001, 10000) != 1 + +------------------------------------------------------------------------ + +# Stage07.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 7254 of 8026 instructions (90.4%). + +## phase 1 — END_PHASE at 0x002B38: 2 necessary condition(s) + 0x002750 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002A48 random(2) == 0 + +## phase 1 — END_PHASE at 0x0031B4: 3 necessary condition(s) + 0x002750 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002B98 hp_pct_test(TCN004, 0) != 1 + 0x003088 random(5) == 0 + +## phase 1 — END_PHASE at 0x003434: 3 necessary condition(s) + 0x002750 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002B98 hp_pct_test(TCN004, 0) != 1 + 0x003214 hp_pct_test(TCN012, 0) != 1 + +## phase 1 — END_PHASE at 0x0036BC: 4 necessary condition(s) + 0x002750 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002B98 hp_pct_test(TCN004, 0) != 1 + 0x003214 hp_pct_test(TCN012, 0) != 1 + 0x00349C read_freg(0) < 600 + +## phase 1 — END_PHASE at 0x003B34: 7 necessary condition(s) + 0x002750 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002B98 hp_pct_test(TCN004, 0) != 1 + 0x003214 hp_pct_test(TCN012, 0) != 1 + 0x00349C read_freg(0) < 600 + 0x0036DC global[0] < 7 + 0x0037FC read_freg(0, 0) >= 300 + 0x0039B8 global[8] != 1 + +## phase 1 — FORCE_END_PHASE at 0x00976C: 2 necessary condition(s) + 0x0095D4 hp_pct_test(ADS151a, 0) != 1 + 0x00963C hp_pct_test(TCN012, 40) != 1 + +## phase 2 — END_PHASE at 0x00D168: 2 necessary condition(s) + 0x00CD80 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00D078 random(2) == 0 + +## phase 2 — END_PHASE at 0x00D7E4: 3 necessary condition(s) + 0x00CD80 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00D1C8 hp_pct_test(TCN004, 0) != 1 + 0x00D6B8 random(5) == 0 + +## phase 2 — END_PHASE at 0x00DA64: 3 necessary condition(s) + 0x00CD80 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00D1C8 hp_pct_test(TCN004, 0) != 1 + 0x00D844 hp_pct_test(TCT012, 0) != 1 + +## phase 2 — END_PHASE at 0x00ECD8: 25 necessary condition(s) + 0x00CD80 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00D1C8 hp_pct_test(TCN004, 0) != 1 + 0x00D844 hp_pct_test(TCT012, 0) != 1 + 0x00DAC4 hp_pct_test(ADN201, 0) != 1 + 0x00DB18 hp_pct_test(ADN202, 0) != 1 + 0x00DB6C hp_pct_test(ADN204, 0) != 1 + 0x00DBC0 hp_pct_test(ADN205, 0) != 1 + 0x00DC14 hp_pct_test(ADN209, 0) != 1 + 0x00DC68 hp_pct_test(ADN211, 0) != 1 + 0x00DCBC hp_pct_test(ADN214, 0) != 1 + 0x00DD10 hp_pct_test(ADN215a, 0) != 1 + 0x00DD64 hp_pct_test(ADN215b, 0) != 1 + 0x00DDB8 hp_pct_test(ADN216, 0) != 1 + 0x00DE0C hp_pct_test(ADN220, 0) == 1 + 0x00DEB8 hp_pct_test(ADN221, 0) == 1 + 0x00DF64 hp_pct_test(ADN222, 0) == 1 + 0x00E010 hp_pct_test(ADN223, 0) == 1 + 0x00E0BC hp_pct_test(ADN224, 0) == 1 + 0x00E168 hp_pct_test(ADN230, 0) == 1 + 0x00E214 hp_pct_test(ADN231, 0) == 1 + 0x00E2C0 hp_pct_test(ADN232, 0) == 1 + 0x00E36C hp_pct_test(ADN233, 0) == 1 + 0x00E418 hp_pct_test(ADN234, 0) == 1 + 0x00E690 squad_survival_pct(TCN004, 99.9) != 0 + 0x00EB5C global[16] != 1 + +## phase 2 — END_PHASE at 0x00F4C0: 7 necessary condition(s) + 0x00CD80 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00D1C8 hp_pct_test(TCN004, 0) != 1 + 0x00D844 hp_pct_test(TCT012, 0) != 1 + 0x00DAC4 hp_pct_test(ADN201, 0) != 1 + 0x00ED40 read_freg(0) < 600 + 0x00EF18 squad_survival_pct(TCN004, 99.9) != 0 + 0x00F344 global[16] != 1 + +## phase 2 — FORCE_END_PHASE at 0x017104: 5 necessary condition(s) + 0x016A98 hp_pct_test(ADN223, 0) != 1 + 0x016C00 unit_state(ADN223) != 1 + 0x016D00 unit_state(ADN232) != 1 + 0x016E00 unit_state(ADN233) != 1 + 0x016F00 unit_state(ADN234) != 1 + +------------------------------------------------------------------------ + +# Stage08.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 6642 of 7610 instructions (87.3%). + +## phase 1 — END_PHASE at 0x0041EC: 2 necessary condition(s) + 0x003594 unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x0037C4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + +## phase 1 — END_PHASE at 0x004DF4: 12 necessary condition(s) + 0x003594 unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x0035E8 hp_pct_test(TCN104, 0) == 1 + 0x00363C hp_pct_test(TCN012, 0) == 1 + 0x003698 read_freg(0) < 600 + 0x00420C global[8] != 1 + 0x004220 global[12] != 1 + 0x004234 global[16] != 1 + 0x004248 global[20] != 1 + 0x00425C global[24] != 1 + 0x004458 hp_pct_test(TCN012, 99.9) != 0 + 0x00457C hp_pct_test(ADN102, 0) != 1 + 0x004C78 global[4] != 1 + +## phase 1 — FORCE_END_PHASE at 0x00C980: 1 necessary condition(s) + 0x00C8BC global[0] != 5 + +## phase 2 — END_PHASE at 0x00FB10: 2 necessary condition(s) + 0x00EEB8 unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x00F0E8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + +## phase 2 — END_PHASE at 0x010EA4: 17 necessary condition(s) + 0x00EEB8 unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x00EF0C hp_pct_test(TCN004, 0) == 1 + 0x00EF60 hp_pct_test(TCN012, 0) == 1 + 0x00EFBC read_freg(0) < 600 + 0x00FB70 hp_pct_test(ADN205, 0) != 1 + 0x00FBC4 hp_pct_test(ADN206, 0) != 1 + 0x00FC18 hp_pct_test(ADN207, 0) != 1 + 0x00FC6C hp_pct_test(ADN208, 0) != 1 + 0x00FCC0 hp_pct_test(ADN209, 0) != 1 + 0x00FD14 hp_pct_test(ADN210, 0) != 1 + 0x00FE50 hp_pct_test(ADN202, 0, 0) != 1 + 0x0104E4 squad_survival_pct(TCN004, 99.9) != 0 + 0x010974 unit_alive(TCN005) != 1 + 0x010A24 unit_alive(TCN006) != 1 + 0x010B4C unit_alive(TCN013) != 1 + 0x010C38 hp_pct_test(TCN012, 99.9) != 0 + 0x010D28 global[28] != 1 + +## phase 2 — FORCE_END_PHASE at 0x015A80: 1 necessary condition(s) + 0x0159BC hp_pct_test(ADN210, 0) != 1 + +------------------------------------------------------------------------ + +# Stage09.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 9008 of 10053 instructions (89.6%). + +## phase 1 — END_PHASE at 0x003990: 2 necessary condition(s) + 0x0035D8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0038D0 random(2) == 0 + +## phase 1 — END_PHASE at 0x003BD8: 2 necessary condition(s) + 0x0035D8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0039E8 hp_pct_test(TCN008, 0) != 1 + +## phase 1 — END_PHASE at 0x00421C: 4 necessary condition(s) + 0x0035D8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0039E8 hp_pct_test(TCN008, 0) != 1 + 0x003C30 hp_pct_test(TCN104, 0) != 1 + 0x004120 random(5) == 0 + +## phase 1 — END_PHASE at 0x0049AC: 7 necessary condition(s) + 0x0035D8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0039E8 hp_pct_test(TCN008, 0) != 1 + 0x003C30 hp_pct_test(TCN104, 0) != 1 + 0x004234 global[0] != 11 + 0x0043F4 read_freg(0, 0) >= 300 + 0x004540 unit_state(TCN104) != 1 + 0x004860 global[4] == 0 + +## phase 1 — END_PHASE at 0x004BFC: 5 necessary condition(s) + 0x0035D8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0039E8 hp_pct_test(TCN008, 0) != 1 + 0x003C30 hp_pct_test(TCN104, 0) != 1 + 0x004234 global[0] != 11 + 0x004A0C read_freg(0) < 600 + +## phase 1 — FORCE_END_PHASE at 0x007BF0: 1 necessary condition(s) + 0x007B2C hp_pct_test(TCN109, 0) != 1 + +## phase 2 — END_PHASE at 0x00AA50: 2 necessary condition(s) + 0x00A698 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00A990 random(2) == 0 + +## phase 2 — END_PHASE at 0x00AC98: 2 necessary condition(s) + 0x00A698 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00AAA8 hp_pct_test(TCN008, 0) != 1 + +## phase 2 — END_PHASE at 0x00B1B4: 5 necessary condition(s) + 0x00A698 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00AAA8 hp_pct_test(TCN008, 0) != 1 + 0x00ACB0 global[0] != 7 + 0x00AE6C unit_state(TCN006) != 1 + 0x00B068 global[4] == 0 + +## phase 2 — END_PHASE at 0x00B79C: 6 necessary condition(s) + 0x00A698 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00AAA8 hp_pct_test(TCN008, 0) != 1 + 0x00ACB0 global[0] != 7 + 0x00B23C builtin7(TCN008, 1, Route_TCN008_p2S, 4294967295, 500) == 1 + 0x00B454 unit_state(TCN006) != 1 + 0x00B650 global[4] == 0 + +## phase 2 — FORCE_END_PHASE at 0x00F018: 1 necessary condition(s) + 0x00EF54 hp_pct_test(TCN009, 0) != 1 + +## phase 3 — END_PHASE at 0x012204: 2 necessary condition(s) + 0x011E4C unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x012144 random(2) == 0 + +## phase 3 — END_PHASE at 0x01244C: 2 necessary condition(s) + 0x011E4C unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x01225C hp_pct_test(TCN008, 0) != 1 + +## phase 3 — END_PHASE at 0x013100: 24 necessary condition(s) + 0x011E4C unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x01225C hp_pct_test(TCN008, 0) != 1 + 0x0124A4 hp_pct_test(ADT301, 0) != 1 + 0x0124F8 hp_pct_test(ADT302, 0) != 1 + 0x012550 unit_state(ADN303) == 1 + 0x0125A8 unit_state(ADN304) == 1 + 0x012600 unit_state(ADN305) == 1 + 0x012658 unit_state(ADN306) == 1 + 0x0126B0 unit_state(ADN307) == 1 + 0x012708 unit_state(ADN311) == 1 + 0x012760 unit_state(ADN312) == 1 + 0x0127B8 unit_state(ADN313) == 1 + 0x012810 unit_state(ADN314) == 1 + 0x012868 unit_state(ADN315) == 1 + 0x0128C0 unit_state(ADN316) == 1 + 0x012918 unit_state(ADN317) == 1 + 0x012970 unit_state(ADN318) == 1 + 0x0129C8 unit_state(ADN319) == 1 + 0x012A20 unit_state(ADN320) == 1 + 0x012A78 unit_state(ADS321) == 1 + 0x012AD0 unit_state(ADS322) == 1 + 0x012B28 unit_state(ADS323) == 1 + 0x012DCC unit_state(TCN006) != 1 + 0x013010 read_freg(global[4]) >= 5 + +## phase 3 — END_PHASE at 0x013680: 6 necessary condition(s) + 0x011E4C unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x01225C hp_pct_test(TCN008, 0) != 1 + 0x0124A4 hp_pct_test(ADT301, 0) != 1 + 0x013118 global[28] == 1 + 0x013290 unit_state(TCN006) != 1 + 0x013534 global[4] == 0 + +## phase 3 — FORCE_END_PHASE at 0x01CA54: 2 necessary condition(s) + 0x01C940 unit_relation(TCN001, ADN320) == 1 + 0x01C990 unit_relation(ADN320, TCN001) != 1 + +------------------------------------------------------------------------ + +# Stage10.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 2578 of 2749 instructions (93.8%). + +## phase 1 — END_PHASE at 0x001310: 2 necessary condition(s) + 0x000FE4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x001234 random(1) == 0 + +## phase 1 — END_PHASE at 0x001590: 2 necessary condition(s) + 0x000FE4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x001370 read_freg(0) < 600 + +## phase 1 — END_PHASE at 0x001BA8: 6 necessary condition(s) + 0x000FE4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x001370 read_freg(0) < 600 + 0x0015E8 hp_pct_test(ADT001, 0) != 1 + 0x001708 read_freg(0, 0) > 300 + 0x001918 hp_pct_test(TCN001, 99.9) != 0 + 0x001A2C global[4] == 0 + +## phase 1 — FORCE_END_PHASE at 0x007CF4: 1 necessary condition(s) + 0x007C0C global[0] > 2 + +------------------------------------------------------------------------ + +# Stage11.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 6805 of 7253 instructions (93.8%). + +## phase 1 — END_PHASE at 0x001EBC: 2 necessary condition(s) + 0x001AD4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x001DCC random(2) == 0 + +## phase 1 — END_PHASE at 0x002538: 3 necessary condition(s) + 0x001AD4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x001F1C hp_pct_test(TCN004, 0) != 1 + 0x00240C random(5) == 0 + +## phase 1 — END_PHASE at 0x0027C0: 3 necessary condition(s) + 0x001AD4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x001F1C hp_pct_test(TCN004, 0) != 1 + 0x0025A0 read_freg(0) < 600 + +## phase 1 — END_PHASE at 0x002A00: 4 necessary condition(s) + 0x001AD4 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x001F1C hp_pct_test(TCN004, 0) != 1 + 0x0025A0 read_freg(0) < 600 + 0x0027E0 global[0] < 10 + +## phase 1 — FORCE_END_PHASE at 0x00A684: 1 necessary condition(s) + 0x00A588 hp_pct_test(ADS151a, 0) != 1 + +## phase 2 — END_PHASE at 0x00C488: 2 necessary condition(s) + 0x00C0A0 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00C398 random(2) == 0 + +## phase 2 — END_PHASE at 0x00CB04: 3 necessary condition(s) + 0x00C0A0 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00C4E8 hp_pct_test(TCN004, 0) != 1 + 0x00C9D8 random(5) == 0 + +## phase 2 — END_PHASE at 0x00CD8C: 3 necessary condition(s) + 0x00C0A0 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00C4E8 hp_pct_test(TCN004, 0) != 1 + 0x00CB6C read_freg(0) < 600 + +## phase 2 — END_PHASE at 0x00D214: 6 necessary condition(s) + 0x00C0A0 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x00C4E8 hp_pct_test(TCN004, 0) != 1 + 0x00CB6C read_freg(0) < 600 + 0x00CDAC global[8] < 6 + 0x00CFA8 hp_pct_test(TCN004, 99.9) != 0 + 0x00D098 global[4] != 1 + +## phase 2 — FORCE_END_PHASE at 0x014728: 7 necessary condition(s) + 0x014044 unit_state(ADS254) != 2 + 0x0141C4 global[28] != 1 + 0x014228 unit_state(ADS254) != 1 + 0x014314 unit_state(ADS255) != 1 + 0x014400 unit_state(ADS256) != 1 + 0x0144EC unit_state(ADS257) != 1 + 0x0145D8 unit_state(ADS258) != 1 + +------------------------------------------------------------------------ + +# Stage12.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 6202 of 6628 instructions (93.6%). + +## phase 1 — END_PHASE at 0x003FE4: 2 necessary condition(s) + 0x00323C unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x0034C0 unit_hp_pct(TCN001, Character_Player_Test) != 0 + +## phase 1 — END_PHASE at 0x005390: 10 necessary condition(s) + 0x00323C unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x003290 hp_pct_test(TCN004, 0) == 1 + 0x0032E4 hp_pct_test(TCN006, 0) == 1 + 0x003338 hp_pct_test(TCN008, 0) == 1 + 0x003394 read_freg(0) <= 1200 + 0x004004 global[4] != 1 + 0x0040E8 global[8] != 1 + 0x0041DC != 1 + 0x00435C hp_pct_test(ADN001, 0) != 1 + 0x005214 global[12] != 1 + +## phase 1 — FORCE_END_PHASE at 0x012824: 2 necessary condition(s) + 0x012434 hp_pct_test(ADN045, 0) != 1 + 0x0124A0 unit_state(ADN045) != 1 + +------------------------------------------------------------------------ + +# Stage13.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 4302 of 5258 instructions (81.8%). + +## phase 1 — END_PHASE at 0x003D60: 2 necessary condition(s) + 0x003268 unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x00343C unit_hp_pct(TCN001, Character_Player_Test) != 0 + +## phase 1 — END_PHASE at 0x006998: 15 necessary condition(s) + 0x003268 unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x0032BC hp_pct_test(TCN004, 0) == 1 + 0x003310 hp_pct_test(TCN006, 0) != 1 + 0x003DC0 hp_pct_test(TCN009, 0) == 1 + 0x004FB0 hp_pct_test(ADN001, 0) != 1 + 0x005CB8 unit_state(TCN009) == 1 + 0x005D8C unit_state(TCN010) == 1 + 0x005E60 unit_state(TCN011) == 1 + 0x00602C unit_state(TCN013) == 1 + 0x006100 unit_state(TCN014) == 1 + 0x0061D4 unit_state(TCN017) == 1 + 0x0062A8 unit_state(TCN018) == 1 + 0x00637C unit_state(TCN019) == 1 + 0x00640C global[4] != 0 + 0x00681C global[8] != 1 + +## phase 1 — FORCE_END_PHASE at 0x00EAA0: 2 necessary condition(s) + 0x00E910 hp_pct_test(ADS051a, 0) != 1 + 0x00E970 hp_pct_test(TCN004, 40) != 1 + +------------------------------------------------------------------------ + +# Stage14.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 3305 of 3709 instructions (89.1%). + +## phase 1 — END_PHASE at 0x0028C0: 2 necessary condition(s) + 0x0024D8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0027D0 random(2) == 0 + +## phase 1 — END_PHASE at 0x002B48: 2 necessary condition(s) + 0x0024D8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002928 read_freg(0) < 600 + +## phase 1 — END_PHASE at 0x0031B0: 10 necessary condition(s) + 0x0024D8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002928 read_freg(0) < 600 + 0x002BA8 hp_pct_test(ADT102, 0) != 1 + 0x002BFC hp_pct_test(ADT103, 0) != 1 + 0x002C50 hp_pct_test(ADT104, 0) != 1 + 0x002CA4 hp_pct_test(ADT105, 0) != 1 + 0x002CF8 hp_pct_test(ADT108, 0) != 1 + 0x002D4C hp_pct_test(ADT114, 0) != 1 + 0x002E90 read_freg(0) > 300 + 0x003034 global[8] != 1 + +## phase 1 — FORCE_END_PHASE at 0x0061D4: 7 necessary condition(s) + 0x005DE0 hp_pct_test(ADT102, 0) != 1 + 0x005E58 hp_pct_test(ADT103, 0) != 1 + 0x005ED0 hp_pct_test(ADT104, 0) != 1 + 0x005F48 hp_pct_test(ADT105, 0) != 1 + 0x005FC0 hp_pct_test(ADT108, 0) != 1 + 0x006038 hp_pct_test(ADT114, 0) != 1 + 0x006070 global[0] > 1 + +## phase 2 — END_PHASE at 0x008324: 1 necessary condition(s) + 0x007FC4 unit_hp_pct(TCN201, Character_Player_Test) != 0 + +## phase 2 — END_PHASE at 0x0085AC: 2 necessary condition(s) + 0x007FC4 unit_hp_pct(TCN201, Character_Player_Test) != 0 + 0x00838C read_freg(0) < 600 + +## phase 2 — END_PHASE at 0x008C24: 6 necessary condition(s) + 0x007FC4 unit_hp_pct(TCN201, Character_Player_Test) != 0 + 0x00838C read_freg(0) < 600 + 0x00860C hp_pct_test(ADT201, 0) != 1 + 0x008750 read_freg(0) >= 300 + 0x008974 hp_pct_test(TCN201, 99.9) != 0 + 0x008AA8 global[8] != 1 + +## phase 2 — FORCE_END_PHASE at 0x00AA94: 1 necessary condition(s) + 0x00A9D0 hp_pct_test(ADT201, 20) != 1 + +------------------------------------------------------------------------ + +# Stage15.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 6767 of 8106 instructions (83.5%). + +## phase 1 — END_PHASE at 0x004AF4: 2 necessary condition(s) + 0x003FFC unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x0041D0 unit_hp_pct(TCN001, Character_Player_Test) != 0 + +## phase 1 — END_PHASE at 0x0064A8: 6 necessary condition(s) + 0x003FFC unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x004050 hp_pct_test(TCN004, 0) == 1 + 0x0040A4 hp_pct_test(TCT006, 0) != 1 + 0x004B5C read_freg(0) >= 900 + 0x00571C hp_pct_test(ADN101, 0) != 1 + 0x00632C global[0] != 1 + +## phase 1 — FORCE_END_PHASE at 0x00C730: 1 necessary condition(s) + 0x00C618 hp_pct_test(ADN101, 0) != 1 + +## phase 2 — END_PHASE at 0x010FE0: 2 necessary condition(s) + 0x010388 unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x0105B8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + +## phase 2 — END_PHASE at 0x012740: 12 necessary condition(s) + 0x010388 unit_hp_pct(TCN001, Character_Player_Test) == 0 + 0x0103DC hp_pct_test(TCN204, 0) == 1 + 0x010430 hp_pct_test(TCN006, 0) == 1 + 0x01048C read_freg(0) < 1200 + 0x011040 hp_pct_test(ADT201, 0) != 1 + 0x011094 hp_pct_test(ADT202, 0) != 1 + 0x011190 global[12] != 1 + 0x011348 >= 10 + 0x01143C hp_pct_test(ADN203, 0) != 1 + 0x012390 squad_survival_pct(TCN205, 99.9) != 0 + 0x0124D4 squad_survival_pct(TCN207, 99.9) != 0 + 0x0125C4 global[8] != 1 + +## phase 2 — FORCE_END_PHASE at 0x017304: 2 necessary condition(s) + 0x017164 hp_pct_test(ADT201, 0) != 1 + 0x017240 global[0] != 1 + +------------------------------------------------------------------------ + +# Stage16.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 836 of 1179 instructions (70.9%). + +## phase 1 — END_PHASE at 0x000988: 2 necessary condition(s) + 0x0005A0 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x000898 random(2) == 0 + +## phase 1 — END_PHASE at 0x000CB0: 2 necessary condition(s) + 0x0005A0 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0009F0 read_freg(0) < 600 + +## phase 1 — END_PHASE at 0x001054: 4 necessary condition(s) + 0x0005A0 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0009F0 read_freg(0) < 600 + 0x000CF8 player_gauge0_test(0) != 1 + 0x000D34 player_gauge1_test(0) != 1 + +## phase 1 — FORCE_END_PHASE at 0x001584: 3 necessary condition(s) + 0x001404 builtin141(TCN001, 1, 2, 0, 0, 0, 1000, 5, 100, 100) != 1 + 0x001524 builtin141(TCN001, 1, 2, 0, -4000, 0, 1000, 5, 100, 100) != 1 + 0x001544 global[0] != 1 + +------------------------------------------------------------------------ + +# Stage18.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 881 of 925 instructions (95.2%). + +## phase 1 — END_PHASE at 0x002958: 1 necessary condition(s) + 0x002898 builtin104() != 1 + +------------------------------------------------------------------------ + +# Stage19.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 528 of 560 instructions (94.3%). + +## phase 1 — END_PHASE at 0x001950: 1 necessary condition(s) + 0x001890 builtin104() != 1 + +------------------------------------------------------------------------ + +# Stage20.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 811 of 846 instructions (95.9%). + +## phase 1 — END_PHASE at 0x00261C: 1 necessary condition(s) + 0x00255C builtin104() != 1 + +------------------------------------------------------------------------ + +# Stage21.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 378 of 411 instructions (92.0%). + +## phase 1 — END_PHASE at 0x001250: 1 necessary condition(s) + 0x001190 builtin104() != 1 + +------------------------------------------------------------------------ + +# Stage22.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 706 of 738 instructions (95.7%). + +## phase 1 — END_PHASE at 0x00208C: 1 necessary condition(s) + 0x001FCC builtin104() != 1 + +------------------------------------------------------------------------ + +# Stage23.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 374 of 406 instructions (92.1%). + +## phase 1 — END_PHASE at 0x001208: 1 necessary condition(s) + 0x001148 builtin104() != 1 + +------------------------------------------------------------------------ + +# Stage24.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 4027 of 4235 instructions (95.1%). + +## phase 1 — END_PHASE at 0x00724C: 18 necessary condition(s) + 0x006860 hp_pct_test(ADT101, 0) != 1 + 0x0068B4 hp_pct_test(ADT102, 0) != 1 + 0x006908 hp_pct_test(ADT103, 0) != 1 + 0x00695C hp_pct_test(ADT107, 0) != 1 + 0x0069B0 hp_pct_test(ADT108, 0) != 1 + 0x006A04 hp_pct_test(ADT109, 0) != 1 + 0x006A58 hp_pct_test(ADT110, 0) == 1 + 0x006B04 hp_pct_test(ADT111, 0) == 1 + 0x006BB0 hp_pct_test(ADT112, 0) == 1 + 0x006C5C hp_pct_test(ADT113, 0) == 1 + 0x006D08 hp_pct_test(ADT114, 0) == 1 + 0x006DB4 hp_pct_test(ADT115, 0) == 1 + 0x006E60 hp_pct_test(ADT122, 0) != 1 + 0x006EB4 hp_pct_test(ADT123, 0) != 1 + 0x006F08 hp_pct_test(ADT126, 0) == 1 + 0x006FB4 hp_pct_test(ADT127, 0) != 1 + 0x007008 hp_pct_test(ADT128, 0) != 1 + 0x00705C hp_pct_test(ADT129, 0) != 1 + +## phase 1 — END_PHASE at 0x007678: 3 necessary condition(s) + 0x006860 hp_pct_test(ADT101, 0) != 1 + 0x0072CC unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0073C8 global[0] >= 100 + +## phase 1 — END_PHASE at 0x007D24: 4 necessary condition(s) + 0x006860 hp_pct_test(ADT101, 0) != 1 + 0x0072CC unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0076D8 hp_pct_test(TCN004, 0) != 1 + 0x0077D4 global[0] >= 100 + +## phase 1 — END_PHASE at 0x007FA4: 4 necessary condition(s) + 0x006860 hp_pct_test(ADT101, 0) != 1 + 0x0072CC unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0076D8 hp_pct_test(TCN004, 0) != 1 + 0x007D84 read_freg(0) < 1800 + +## phase 1 — FORCE_END_PHASE at 0x00C114: 3 necessary condition(s) + 0x00BB08 unit_state(ADT101) != 1 + 0x00BDE8 unit_state(ADT108) != 1 + 0x00C090 global[80] != 1 + +------------------------------------------------------------------------ + +# Stage25.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 9522 of 9936 instructions (95.8%). + +## phase 1 — END_PHASE at 0x0173F4: 2 necessary condition(s) + 0x01705C unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x017158 global[0] >= 100 + +## phase 1 — END_PHASE at 0x017A50: 3 necessary condition(s) + 0x01705C unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x017454 hp_pct_test(TCN004, 0) != 1 + 0x017550 global[0] >= 100 + +## phase 1 — END_PHASE at 0x017E48: 4 necessary condition(s) + 0x01705C unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x017454 hp_pct_test(TCN004, 0) != 1 + 0x017AB0 read_freg(0) < 1200 + 0x017BAC global[0] >= 100 + +## phase 1 — FORCE_END_PHASE at 0x01C28C: UNREACHABLE from any static entry + (started from the trigger queue at `phase+272`, by data not code) + +------------------------------------------------------------------------ + +# Stage26.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 3896 of 5604 instructions (69.5%). + +## phase 1 — END_PHASE at 0x003D80: 2 necessary condition(s) + 0x0039C8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x003CC0 random_rand(2) == 0 + +## phase 1 — END_PHASE at 0x0043C4: 3 necessary condition(s) + 0x0039C8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x003DD8 hp_pct_test(TCN004, 0) != 1 + 0x0042C8 random_rand(5) == 0 + +## phase 1 — END_PHASE at 0x0045CC: 3 necessary condition(s) + 0x0039C8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x003DD8 hp_pct_test(TCN004, 0) != 1 + 0x0043DC global[0] != 8 + +## phase 1 — END_PHASE at 0x004960: 5 necessary condition(s) + 0x0039C8 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x003DD8 hp_pct_test(TCN004, 0) != 1 + 0x0043DC global[0] != 8 + 0x00462C read_freg(0) < 900 + 0x004828 global[0] != 0 + +## phase 1 — FORCE_END_PHASE at 0x00FF5C: 1 necessary condition(s) + 0x00FE2C hp_pct_test(TCT019, 50) != 1 + +------------------------------------------------------------------------ + +# Stage27.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 2468 of 3031 instructions (81.4%). + +## phase 1 — END_PHASE at 0x0024E0: 2 necessary condition(s) + 0x002128 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002420 random_rand(2) == 0 + +## phase 1 — END_PHASE at 0x002B24: 3 necessary condition(s) + 0x002128 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002538 hp_pct_test(TCN004, 0) != 1 + 0x002A28 random_rand(5) == 0 + +## phase 1 — END_PHASE at 0x002D74: 3 necessary condition(s) + 0x002128 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002538 hp_pct_test(TCN004, 0) != 1 + 0x002B84 read_freg(0) < 1200 + +## phase 1 — END_PHASE at 0x003850: 22 necessary condition(s) + 0x002128 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x002538 hp_pct_test(TCN004, 0) != 1 + 0x002B84 read_freg(0) < 1200 + 0x002DCC hp_pct_test(ADN113, 0) != 1 + 0x002E20 hp_pct_test(ADN114, 0) != 1 + 0x002E74 hp_pct_test(ADN115, 0) != 1 + 0x002EC8 hp_pct_test(ADN116, 0) != 1 + 0x002F1C hp_pct_test(ADN117, 0) != 1 + 0x002F70 hp_pct_test(ADN118, 0) != 1 + 0x002FC4 hp_pct_test(ADN119, 0) != 1 + 0x003018 hp_pct_test(ADN107, 0) != 1 + 0x00306C hp_pct_test(ADN108, 0) == 1 + 0x003118 hp_pct_test(ADN109, 0) != 1 + 0x00316C hp_pct_test(ADN110, 0) != 1 + 0x0031C0 hp_pct_test(ADN111, 0) != 1 + 0x003214 hp_pct_test(ADN112, 0) != 1 + 0x003268 hp_pct_test(ADN101, 0) != 1 + 0x0032BC hp_pct_test(ADN102, 0) != 1 + 0x003310 hp_pct_test(ADN103, 0) != 1 + 0x003364 hp_pct_test(ADN104, 0) != 1 + 0x003514 unit_state(TCN005) != 1 + 0x003710 hp_pct_test(TCN004, 80) != 1 + +## phase 1 — FORCE_END_PHASE at 0x0088A0: 1 necessary condition(s) + 0x0087DC hp_pct_test(ADN119, 50) != 1 + +------------------------------------------------------------------------ + +# Stage28.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 2193 of 2401 instructions (91.3%). + +## phase 1 — END_PHASE at 0x002488: 2 necessary condition(s) + 0x00218C unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0023DC random_rand(1) == 0 + +## phase 1 — END_PHASE at 0x0028C0: 4 necessary condition(s) + 0x00218C unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0024E0 hp_pct_test(TCN003, 0) != 1 + 0x002534 hp_pct_test(TCN002, 0) != 1 + 0x0026E8 read_freg(0) > 420 + +## phase 1 — END_PHASE at 0x002C2C: 4 necessary condition(s) + 0x00218C unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x0024E0 hp_pct_test(TCN003, 0) != 1 + 0x002920 read_freg(0) < 1200 + 0x002A4C unit_hp_pct(TCN001, ELLEN) != 0 + +## phase 1 — FORCE_END_PHASE at 0x006F24: 1 necessary condition(s) + 0x006E60 hp_pct_test(ADT112, 0) != 1 + +------------------------------------------------------------------------ + +# Stage29.ssb — what each phase exit requires + +Generated by `tools/re-capture/isl_report.py phase-guards`. + +A condition is listed when it DOMINATES the exit: every path from an +entry to that `END_PHASE` passes through it, so it is NECESSARY for the +phase to end that way. Reachability alone is the wrong query here — +in a poll loop both successors reach the exit. + +CFG reached 14755 of 19779 instructions (74.6%). + +## phase 1 — END_PHASE at 0x010910: 3 necessary condition(s) + 0x00CD3C global[56] == 1 + 0x010548 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x010644 global[0] >= 100 + +## phase 1 — END_PHASE at 0x010F6C: 4 necessary condition(s) + 0x00CD3C global[56] == 1 + 0x010548 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x010970 hp_pct_test(TCN004, 0) != 1 + 0x010A6C global[0] >= 100 + +## phase 1 — END_PHASE at 0x0111EC: 4 necessary condition(s) + 0x00CD3C global[56] == 1 + 0x010548 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x010970 hp_pct_test(TCN004, 0) != 1 + 0x010FCC hp_pct_test(TCT006, 0) != 1 + +## phase 1 — END_PHASE at 0x011514: 5 necessary condition(s) + 0x00CD3C global[56] == 1 + 0x010548 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x010970 hp_pct_test(TCN004, 0) != 1 + 0x010FCC hp_pct_test(TCT006, 0) != 1 + 0x011254 read_freg(0) < 1200 + +## phase 1 — END_PHASE at 0x011814: 7 necessary condition(s) + 0x00CD3C global[56] == 1 + 0x010548 unit_hp_pct(TCN001, Character_Player_Test) != 0 + 0x010970 hp_pct_test(TCN004, 0) != 1 + 0x010FCC hp_pct_test(TCT006, 0) != 1 + 0x011254 read_freg(0) < 1200 + 0x011534 global[52] < 14 + 0x011554 global[60] != 1 + +## phase 1 — FORCE_END_PHASE at 0x038960: UNREACHABLE from any static entry + (started from the trigger queue at `phase+272`, by data not code) diff --git a/docs/re/structures/isl-phase-guards.md b/docs/re/structures/isl-phase-guards.md index 30267819..edc4be57 100644 --- a/docs/re/structures/isl-phase-guards.md +++ b/docs/re/structures/isl-phase-guards.md @@ -76,9 +76,49 @@ static entry**. That agrees with the independently measured 389 unreachable routines: they are started from the **trigger queue at `phase+272`**, by data rather than code. So a purely static reading cannot say what forces those exits. -## 🟡 Not settled +## ✅ All 28 stages — [`../data/isl-phase-guards-all.txt`](../data/isl-phase-guards-all.txt) -* **Only Stage 02 is committed.** The other 27 generate from the same command. +`isl_report.py phase-guards` runs the whole disc. **177 phase exits**, of +which only **5 (2.8 %)** are reachable from no static entry. + +| | | +|---|---| +| CFG reach, best | Stage 25 — 95.8 % | +| CFG reach, worst | Stage 26 — 69.5 % | +| median conditions per exit | ~4 | + +### ✅ An independent cross-check, 6 / 6 + +The six **tutorial** stages (S18–S23) each have exactly **one** exit with exactly +**one** dominating condition, and it is the same one every time: + +``` +END_PHASE <- builtin104() != 1 +``` + +[`isl-builtins.md`](isl-builtins.md) reached built-in **104** from a completely +different direction — call-site usage — and recorded it as *"S18–S23 only … +followed by `wait_s` 39/39, preceded by `end_coroutine` 37/39 … a textbook poll +loop"*. Usage said it was the tutorial's polled test; dominance says it is the +tutorial's clear condition. **Two unrelated methods, six for six.** That the +1.0-condition uniformity turned out to be real rather than a degenerate result is +the check worth having run. + +### Stage 16, the corpus outlier, also reads + +`mission-script-ssb.md` flags S16 as the stage whose script may be compiled C++. +Its exits resolve anyway, and sensibly: + +``` +ph1 END_PHASE read_freg(0) < 600 ; player_gauge0_test(0) != 1 ; player_gauge1_test(0) != 1 +ph1 FORCE_END_PHASE builtin141(TCN001, 1, 2, 0, 0, 0, 1000, 5, 100, 100) != 1 ; + builtin141(TCN001, 1, 2, 0, -4000, 0, 1000, 5, 100, 100) != 1 ; global[0] != 1 +``` + +The two `builtin141` calls differ in one argument (`0` vs `-4000`), which is the +shape of a position or zone test — but it is unread, so it is not named. + +## 🟡 Not settled * **Dominance gives necessary, not sufficient, conditions.** A dominator set does not say the phase ends *when* they all hold, only that it cannot end unless they do. Turning these into a simulator's exit test needs the sufficient side. diff --git a/tools/re-capture/isl_report.py b/tools/re-capture/isl_report.py index db66b722..484e47ce 100644 --- a/tools/re-capture/isl_report.py +++ b/tools/re-capture/isl_report.py @@ -11,6 +11,7 @@ generator in the tree is the point of this file. isl_report.py phase-ends -> every END_PHASE with its context isl_report.py conditions -> every condition site, comparand resolved isl_report.py phase-guards -> the NECESSARY conditions for each exit + isl_report.py phase-guards -> the same for every Stage*.ssb it holds The "needs the coroutine entry points" blocker recorded here is REFUTED: the instruction stream is FLAT and `isl.linear_offsets` reaches 25705/25705 call @@ -19,6 +20,7 @@ stopping at op 20 (`ret`), which in a coroutine VM is a yield, not an end of code -- see `docs/re/isl-stream-is-flat.md`. """ import collections +import os import sys import isl @@ -162,7 +164,25 @@ def emit_phase_guards(b, path): def main(): + # The dominator pass over a large stage is memory-hungry and once OOM-KILLED + # a run on this 15 GB box. Cap the address space so a bad input fails this + # process instead of the machine. + try: + import resource + resource.setrlimit(resource.RLIMIT_AS, (10 * 1024 ** 3,) * 2) + except Exception: + pass path = sys.argv[1] + if os.path.isdir(path): + import glob + files = sorted(glob.glob(os.path.join(path, 'Stage*.ssb'))) + for i, f in enumerate(files): + if i: print(); print('-' * 72); print() + {'calls': emit_calls, 'phase-ends': emit_phase_ends, + 'conditions': emit_conditions, + 'phase-guards': emit_phase_guards}[sys.argv[2]]( + isl.load(f), os.path.basename(f)) + return b = isl.load(path) name = path.replace('\\', '/').split('/')[-1] {'calls': emit_calls, 'phase-ends': emit_phase_ends,