re: phase-guards for all 28 stages, and a 6/6 cross-check from an unrelated method
isl_report.py now accepts a directory, so the dominance analysis runs over the whole
disc: data/isl-phase-guards-all.txt, 177 phase exits, of which only 5 (2.8%) are
reachable from no static entry. CFG reach ranges 69.5% (S26) to 95.8% (S25), median
about 4 dominating conditions per exit.
The lopsided number in the per-stage table was the six TUTORIAL stages, S18-S23, each
with exactly ONE exit and exactly ONE dominating condition. That could have been a
degenerate result, so I looked: it is the same condition in all six,
END_PHASE <- builtin104() != 1
and isl-builtins.md reached built-in 104 from call-site USAGE alone -- "S18-S23 only,
followed by wait_s 39/39, preceded by end_coroutine 37/39, a textbook poll loop".
Usage said 104 is the tutorial's polled test; dominance says it is the tutorial's
clear condition. Two unrelated methods, six for six.
Stage 16 -- the corpus outlier whose script may be compiled C++ -- resolves as well:
read_freg(0) < 600, player_gauge0_test, player_gauge1_test, and two builtin141 calls
differing in a single argument (0 vs -4000), which is the shape of a position or zone
test. builtin141 is unread, so it is not named.
Stage 02's separate artefact regenerates byte-identical.
Also added: an RLIMIT_AS cap in isl_report's entry point. The dominator pass
OOM-killed a run earlier on this 15 GB box; a bad input should now fail the process
rather than the machine.
Still not settled and stated in the doc: dominance gives necessary, not sufficient,
conditions; the 5 unreachable exits need the trigger queue at phase+272; builtin104,
builtin141 and builtin7 all appear in clear conditions and are unread.
This commit is contained in:
@@ -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 <dir> 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`.
|
||||
|
||||
1452
docs/re/data/isl-phase-guards-all.txt
Normal file
1452
docs/re/data/isl-phase-guards-all.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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 <dir> 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.
|
||||
|
||||
@@ -11,6 +11,7 @@ generator in the tree is the point of this file.
|
||||
isl_report.py <StageNN.ssb> phase-ends -> every END_PHASE with its context
|
||||
isl_report.py <StageNN.ssb> conditions -> every condition site, comparand resolved
|
||||
isl_report.py <StageNN.ssb> phase-guards -> the NECESSARY conditions for each exit
|
||||
isl_report.py <dir> 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,
|
||||
|
||||
Reference in New Issue
Block a user