#!/usr/bin/env python3 """Regenerate the committed ISL artefacts under `docs/re/data/`. isl_report.py 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 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 isl_report.py schedule -> the phase timeline tables 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 '' rhs = c['rhs'] if c['rhs'] is not None else '' 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)) print() print('`precond` = necessary: the exit cannot happen unless it holds.') print('`TRIGGER` = also SUFFICIENT: once it holds the exit is unavoidable.') print('An exit with no TRIGGER is not fired by a branch — a timeout exit is') print('fired by time passing, which is not a property of the graph.') 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 '' rhs = c['rhs'] if c['rhs'] is not None else '' tag = 'TRIGGER ' if c.get('sufficient') else 'precond ' print(' %s0x%06X %s %s %s' % (tag, c['off'], lhs, c['rel'], rhs)) def emit_schedule(b, path): """The per-phase timeline: what the script launches, and when.""" sch = isl.schedule(b) print('# %s — phase timelines' % path) print() print('Generated by `tools/re-capture/isl_report.py schedule`.') print() print('Each phase ends with a table of `(routine offset, time in seconds, kind)`.') print('%d entries.' % len(sch)) for ph in sorted({p for p, _o, _t, _k in sch}): rows = [r for r in sch if r[0] == ph] print() print('## phase %d — %d scheduled routines' % (ph, len(rows))) for _p, off, t, k in sorted(rows, key=lambda r: (r[2], r[1])): print(' t=%-8g kind=%d -> 0x%06X' % (t, k, off)) 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, 'schedule': emit_schedule}[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, 'schedule': emit_schedule}[sys.argv[2]](b, name) if __name__ == '__main__': main()