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/docs/re/structures/isl-unit-args.md
Sylpheed RE agent 126539b875 re: derive UNIT_ARG from the implementations -- 31 built-ins take a unit, not 31 of 55
isl.py's UNIT_ARG decides whether a built-in's slot-4 operand prints as a unit name
or a raw number.  It was inferred statistically from operand ranges and, by its own
comment, listed a slot "only when the ratio stayed below 1.0" -- conservative.

The vtable base makes it a lookup instead: every unit-taking built-in's implementation
opens with lwz 324(phase) / lwz 4(argbase) / rlwinm 2,0,29 / lwzx / lwz 4(rec).  Read
directly for all 147:

  implementation indexes [phase+324] by an argument   55
  of the statistical set's 31, confirmed              31  (zero false positives)
  UNIT_ARG claims a unit, implementation does not      0
  implementation says unit, UNIT_ARG missed it        24

The 24 include builtin80, group_ratio_pct, is_engaged, set_unit_flags,
squadron_trace, wait_units_ready and deploy_and_wait.  Hand-verified by reading
builtin7, 16, 80, 105, 117 and 136.

Recorded because it nearly passed: my FIRST control -- whether the additions' operands
resolve to a symbol-table-2 index -- is worthless.  The additions score 100.0%, but so
do the 31 baseline (100.0%) AND the 92 built-ins in neither set (99.3%).  Symtab 2 is
dense enough that almost any small integer lands in it.  A control the negative class
also passes is not evidence.

The control that discriminates is the tag word: a symbol operand is a two-word pair
whose first word is the constant 1, so slot0 == 1 exactly when slot 4 is a unit --
100.0% (13677 calls) / 100.0% (140) / 2.5% (2903).  A 40x separation.

Artefacts: isl-stage02.txt and -phase-ends.txt regenerate byte-identical; -conditions
changes on 28 sites, every diff line pairing, each a raw number becoming a unit name.

Left unnamed on purpose: all 24.  builtin80 returns a small enum (tested 0..4 in a
switch) but its body past the liveness check is unread; builtin103 is a predicate over
[phase+10152]/[phase+10156]; builtin105 tests a unit record's +16 against 4.
2026-08-27 05:45:10 +00:00

94 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ✅ Which built-ins take a unit — read from the implementations, and the old set was short
`isl.py`'s `UNIT_ARG` decides whether a built-in's slot-4 operand is printed as
a **unit name** or as a raw number. It was built **statistically**, from operand
ranges, and its own comment says slots were listed *"only when the ratio stayed
below 1.0"* — i.e. only when every observed value resolved. That is
conservative, and it was.
## The direct method
[`isl-builtin-dispatch`](isl-builtin-dispatch.md) makes this a lookup: a
built-in's stub tail-calls a fixed slot of the `ScriptPhase` vtable at
`0x820A84BC`, so the implementation can simply be read. Every unit-taking
built-in opens the same way — this is `unit_state`, `builtin80`, `builtin117`
and `builtin136`, character for character:
```
lwz r10, 324(r31) ; the unit array
lwz r11, 4(r30) ; r30 = the local[] base, so this is local[4]
rlwinm r11, r11, 2, 0, 29 ; x4
lwzx r11, r11, r10 ; -> the record
lwz r11, 4(r11) ; the handle
cmpli cr6, 0, r11, 0x0 ; "is this squadron gone?"
```
## ✅ Result: 31 → 55
| | |
|---|---|
| built-ins whose implementation indexes `[phase+324]` by an argument | **55** |
| of the statistical set's 31, confirmed | **31 — all of them** |
| **UNIT_ARG claims a unit, the implementation does not** | **0** |
| **implementation says unit, UNIT_ARG missed it** | **24** |
The 24: `21, 22, 23, 32, 42, 44, 46 (squadron_trace), 49, 50, 51, 55, 60, 61,
72 (group_ratio_pct), 80, 83, 94 (is_engaged), 101, 109 (set_unit_flags), 117,
136, 137 (wait_units_ready), 141, 142 (deploy_and_wait)`.
Zero false positives is worth stating on its own: the statistical method was
**right about everything it claimed** and only too cautious about what it
omitted.
## ⚠️ The first control I chose was worthless — recorded because it nearly passed
I first checked whether the additions' slot-4 operands resolve to a symbol-table-2
index. They did, **100.0 %** — and it means nothing:
| set | operands resolving to a symtab-2 unit |
|---|---|
| the 31 baseline | 100.0 % |
| the 24 additions | 100.0 % |
| **the 92 built-ins in neither set** | **99.3 %** |
Symbol table 2 is dense enough that almost any small integer lands in it, so the
test does not discriminate. A control that the negative class also passes is not
evidence, and this one was one careless glance from being written up as proof.
## ✅ The control that does discriminate
`isl-builtins.md` documents that a symbol operand is a **two-word pair** — a tag
holding the constant 1, then the index. So slot 0 should be 1 exactly when
slot 4 is a unit:
| set | calls with `slot0 == 1` |
|---|---|
| the 31 baseline | **100.0 %** (13 677 calls) |
| the 24 additions | **100.0 %** (140 calls) |
| the 92 in neither set | **2.5 %** (2 903 calls) |
A 40× separation, and the additions sit exactly on the positive class.
## Effect on the artefacts
`data/isl-stage02.txt` and `-phase-ends.txt` regenerate **byte-identical**;
`-conditions.txt` changes on 28 sites, every diff line pairing, all of them a
raw number becoming a unit name:
```
- 0x01B6C0 if builtin80(0x8B) == 0 -> + 0x01B6C0 if builtin80(TCT206) == 0
```
## 🟡 Not settled
* **The 24 are still unnamed.** Knowing an argument is a unit is not knowing what
the built-in does. `builtin80` (69 operands disc-wide) is tested against
0, 1, 2, 3, 4 in a switch chain, so it returns a small enumeration — but I am
not naming it from that, and its body past the liveness check is unread.
* `builtin103` (`0x8226BFA8`) is a predicate over **`[phase+10152]` and
`[phase+10156]`**, neighbours of a value read out at `+10160`; it takes no unit.
The fields have 9, 7 and 1 writers respectively, none of them read.
* `builtin105` (`0x8226BFF0`) tests a unit record's **`+16` against 4**. What
`rec+16` holds is not established — `isl-builtins.md` only rules out its being
what `unit_state` reads.