This repository has been archived on 2026-09-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Syplheed-Reborn/tools/re-capture/isl_report.py
Sylpheed RE agent b636ac9d4e 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.
2026-08-27 06:19:44 +00:00

195 lines
8.2 KiB
Python

#!/usr/bin/env python3
"""Regenerate the committed ISL artefacts under `docs/re/data/`.
isl_report.py <StageNN.ssb> calls -> the call-site census + a listing
The artefact was produced by an uncommitted one-off, so it drifted out of date
twice: once when operand staging was fixed (calls printed with too few
arguments) and once when three built-in names were corrected. Keeping the
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
sites across all 28 stages. What broke the naive linear decode was `isl.dis`
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
import isl_cfg
def census(b):
cs = isl.call_sites(b)
return cs, collections.Counter(bid for _, bid, _ in cs)
def emit_calls(b, path):
cs, h = census(b)
s1, s2 = isl.symbols(b, 1), isl.symbols(b, 2)
print('# %s — ISL disassembly artefacts' % path)
print()
print('Generated by `tools/re-capture/isl_report.py calls`.')
print()
print('%d call sites, %d distinct built-ins' % (len(cs), len(h)))
for bid, n in h.most_common():
print(' builtin %-4d %5d site(s)' % (bid, n))
print()
print('## phase-control sites')
for bid, nm in ((6, 'END_PHASE'), (62, 'FORCE_END_PHASE'),
(39, 'MARK_LAST_PHASE'), (40, 'mark_not_last')):
offs = [off for off, b2, _ in cs if b2 == bid]
print('%-3d %-18s %2d: %s'
% (bid, nm, len(offs), ' '.join('0x%x' % o for o in offs)))
print()
print('## named built-ins used, by traffic')
for bid, n in h.most_common():
nm = isl.BUILTIN.get(bid)
if nm:
print(' %-3d %-24s %4d' % (bid, nm, n))
print()
print('## phase code bases')
print('Each phase has its OWN base; the file header offset is not it.')
print(' ' + ' '.join('0x%x' % x for x in isl.phase_bases(b)))
print()
print('## disassembly into the first END_PHASE')
target = [off for off, bid, _ in cs if bid == 6][0]
start = isl.resync(b, target)
print('resync from 0x%X' % start)
for line in isl.dis(b, start, 64, code_base=0x24, sym2=s2, sym1=s1):
print(line)
def emit_phase_ends(b, path):
"""Every phase-ending call with the instructions that lead into it."""
offs = isl.linear_offsets(b)
idx = {o: k for k, o in enumerate(offs)}
bases = isl.phase_bases(b)
s1, s2 = isl.symbols(b, 1), isl.symbols(b, 2)
ends = [(o, bid) for o, bid, _ in isl.call_sites(b) if bid in (6, 62)]
print('# %s — where each phase ends' % path)
print()
print('Generated by `tools/re-capture/isl_report.py phase-ends`.')
print('Decoded with `stop_at_ret=False`; a `ret` is a coroutine YIELD, so')
print('the listing continues past it.')
print()
print('phase code bases: ' + ' '.join('0x%x' % x for x in bases))
print('%d phase-ending call(s): %d END_PHASE, %d FORCE_END_PHASE'
% (len(ends), sum(1 for _, b2 in ends if b2 == 6),
sum(1 for _, b2 in ends if b2 == 62)))
for o, bid in ends:
ph = sum(1 for x in bases if x <= o)
k = idx.get(o)
if k is None:
print('\n## 0x%X builtin %d — NOT on the linear stream' % (o, bid))
continue
print('\n## phase %d — builtin %d (%s) at 0x%X'
% (ph, bid, isl.BUILTIN.get(bid, '?'), o))
for line in isl.dis(b, offs[max(0, k - 16)], 22,
code_base=bases[ph - 1], sym2=s2, sym1=s1,
stop_at_ret=False):
print(' ' + line)
def emit_conditions(b, path):
"""Every condition site with its comparand — what `data/isl-stage02-conditions.txt`
never had a generator for."""
import collections
cs = isl_cfg.conditions(b, isl.symbols(b, 1), isl.symbols(b, 2))
bases = isl.phase_bases(b)
print('# %s — condition sites, comparands resolved' % path)
print()
print('Generated by `tools/re-capture/isl_report.py conditions`.')
print()
print('The deque ops are an expression stack: `push.i` saves the comparand,')
print('the right-hand side is evaluated (its result lands in `special[0]`),')
print('`pop.i` restores the comparand into `special[1]`, then `cmp.i` compares.')
print()
print('Operands come from a CFG dataflow fixpoint (`isl_cfg.py`), joining each')
print('block over its ACTUAL predecessors — not from a linear walk.')
print()
print('%d condition sites; phase bases %s'
% (len(cs), ' '.join('0x%x' % x for x in bases)))
h = collections.Counter(c['lhs'].split('(')[0] for c in cs if c['lhs'] and '(' in c['lhs'])
print()
print('## most-tested predicates')
for k, n in h.most_common(20):
print(' %-28s %4d' % (k, n))
for ph in range(1, len(bases) + 1):
rows = [c for c in cs if c['phase'] == ph]
print()
print('## phase %d%d sites' % (ph, len(rows)))
for c in rows:
lhs = c['lhs'] if c['lhs'] is not None else '<unknown: no static entry>'
rhs = c['rhs'] if c['rhs'] is not None else '<unknown>'
print(' 0x%06X if %s %s %s -> 0x%X'
% (c['off'], lhs, c['rel'], rhs, c['target']))
def emit_phase_guards(b, path):
"""The conditions that DOMINATE each phase exit — the per-phase clear condition."""
rows, reached, total = isl_cfg.dominating_conditions(b)
print('# %s — what each phase exit requires' % path)
print()
print('Generated by `tools/re-capture/isl_report.py phase-guards`.')
print()
print('A condition is listed when it DOMINATES the exit: every path from an')
print('entry to that `END_PHASE` passes through it, so it is NECESSARY for the')
print('phase to end that way. Reachability alone is the wrong query here —')
print('in a poll loop both successors reach the exit.')
print()
print('CFG reached %d of %d instructions (%.1f%%).' % (reached, total, 100.0 * reached / total))
for r in rows:
nm = isl.BUILTIN.get(r['builtin'], 'builtin%d' % r['builtin'])
if r['conds'] is None:
print()
print('## phase %d%s at 0x%06X: UNREACHABLE from any static entry'
% (r['phase'], nm, r['end']))
print(' (started from the trigger queue at `phase+272`, by data not code)')
continue
print()
print('## phase %d%s at 0x%06X: %d necessary condition(s)'
% (r['phase'], nm, r['end'], len(r['conds'])))
for c in r['conds']:
lhs = c['lhs'] if c['lhs'] is not None else '<unknown>'
rhs = c['rhs'] if c['rhs'] is not None else '<unknown>'
print(' 0x%06X %s %s %s' % (c['off'], lhs, c['rel'], rhs))
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,
'conditions': emit_conditions,
'phase-guards': emit_phase_guards}[sys.argv[2]](b, name)
if __name__ == '__main__':
main()