Disassembling the three Stage-02 entry_a targets shows opcodes 0x19 and 0x1A, and the
ISL dispatcher's table has 25 entries (cmplwi 0x18). They are not instructions. Each
phase region ENDS with a trailing data table of 8-byte typed records -- tag 0x19 = int,
tag 0x1A = IEEE float (0.0, 0.5, 1.0, 4.0) -- and entry_a is where it starts.
Confirmed across the disc: in 44 of 44 phases the first offset whose opcode exceeds
0x18 is exactly that phase's entry_a, with zero exceptions, and only two tags ever
appear (1394 x 0x19, 675 x 0x1A). So the record is
0x1883, base, size, 0, code_end, force_end_handler
one boundary and one entry, not two entries as the previous commit said.
That also retires this thread's own "82 of 88 land on a valid instruction = 93.2% vs a
38.6% control" as TOO WEAK a test: a data record has length 8 and passes "nonzero,
even". The entry_b result stands on different evidence -- those targets were matched
against isl.call_sites(), an independent enumeration.
isl.linear_offsets was decoding all 2069 data records as instructions, 1.23% of the
stream. Now each phase's walk stops at its boundary:
decoded instructions 168251 -> 166182 (= 168251 - 2069, as predicted)
opcode > 0x18 2069 -> 0
call sites covered 25705/25705 -> 25705/25705
exits unreachable 0 -> 0
conditions unknown 400 -> 400
Recorded because the first attempt at the fix was worse than the bug: it destroyed 36%
of the stream (168251 -> 107596, exits 0 -> 74) because linear_offsets is ONE global
walk from the first phase base, so stopping at phase 1's table lost every later phase.
It has to skip the region and resume at the next base. A count moving hard in the
wrong direction is the same signal as one that will not move.
Still open: the table's contents are undecoded -- its int values land on the
instruction stream 46/51 against a 29.5% chance rate, but 0 of them are unreached
run-starts, so this is not what starts the unreachable code either.
126 lines
5.7 KiB
Markdown
126 lines
5.7 KiB
Markdown
# ✅ The mission-level `0x1883` record: one entry point and one code/data boundary
|
||
|
||
Every phase exit in all 28 stages is now reachable. `data/isl-phase-guards-all.txt`
|
||
went from **5 of 177 exits unreachable** to **0**.
|
||
|
||
## The hunt, including the part that failed
|
||
|
||
The first step was the cheap one: take each unreached routine's entry offset and
|
||
look for it as a word anywhere in the file. **It is not there**, in any encoding:
|
||
|
||
| entry encoded as | appears as a word | control (reached offsets) |
|
||
|---|---|---|
|
||
| phase-relative | 6.6 % | **11.5 %** |
|
||
| absolute | 1.6 % | 3.3 % |
|
||
| phase-relative / 4 | 1.6 % | 6.6 % |
|
||
| absolute / 4 | 0.0 % | 8.2 % |
|
||
|
||
Every variant sits **at or below** the control, so nothing in the bytecode names
|
||
these routines. That is a real negative, and it ruled out the whole family of
|
||
"some instruction operand points at them".
|
||
|
||
It also ruled out *dead code*: the 3 069 unreached instructions in Stage 02
|
||
contain **485 calls**, including `start_coroutine` ×75, `squadron_attack` ×59,
|
||
`set_group_speed` ×42 and `objective_marker` ×13. That is live mission logic.
|
||
|
||
## ✅ The answer is in the mission-level stream
|
||
|
||
`isl-bytecode.md` records that the stream at `+0x24` holds three `0x1883` records,
|
||
one per phase, whose operand is the phase's code base, and notes they each end
|
||
"in a pair of plausible ISL entry offsets". They are exactly that. The record is
|
||
|
||
```
|
||
0x1883, base_delta, size, 0, entry_a, entry_b ; entries PHASE-RELATIVE
|
||
```
|
||
|
||
~~**Measured over all 28 stages: 82 of 88 of those values land on a valid
|
||
instruction — 93.2 %, against a 38.6 % chance rate.**~~
|
||
⚠️ **That test was too weak** — see *What `entry_a` really is* below. A trailing
|
||
data record has length 8 and so passes "nonzero, even length"; the 93.2 % counted
|
||
data as code. The `entry_b` result stands on a different footing: those targets
|
||
were matched against `isl.call_sites()`, an independent enumeration.
|
||
|
||
And for Stage 02 the second entry of each record is the phase's force-end
|
||
handler:
|
||
|
||
```
|
||
base 0x0000E4 -> 0x014848, 0x01482C <- 0x1482C was an unreachable exit
|
||
base 0x014AA8 -> 0x024A0C, 0x0249F0
|
||
base 0x024B4C -> 0x034AC8, 0x034A10 <- 0x34A10 was an unreachable exit
|
||
```
|
||
|
||
Both of Stage 02's unreachable exits are named here, and phase 2's `0x249F0` —
|
||
already reachable — is the same slot, which is the consistency check.
|
||
|
||
Seeding these as CFG entries: **exits unreachable 5 → 0** across the disc.
|
||
|
||
🔑 It also *reads*: those exits now show **0 necessary conditions**, because they
|
||
are entry points rather than code reached through tests. A handler the engine can
|
||
enter directly, with no preconditions, is what `FORCE_END_PHASE` should look like.
|
||
|
||
## ⚠️ Seeded in one place, and the count did not move
|
||
|
||
The first attempt added the entries to `conditions()` and reported reach
|
||
**85.0 % → 85.0 %**, exits **5 → 5**. Nothing moved, which is the signal.
|
||
`dominating_conditions()` builds its **own** entry set and did not use the one I
|
||
had patched — the same fix-the-instance-not-the-class mistake that cost 22× its
|
||
own size earlier in this corpus. With both patched: exits **5 → 0**.
|
||
|
||
## 🟡 Not settled
|
||
|
||
* **Reach only went 85.0 % → 85.2 %.** These records name a handful of routines,
|
||
not the ~15 % of code still unreached. What starts *the rest* is still open —
|
||
and the negative above says it is not an operand in the file.
|
||
* **`entry_a` is unidentified.** `entry_b` is the force-end handler in the three
|
||
Stage-02 records; what the first entry of each pair is has not been checked.
|
||
* **6 of 88 values do not land on an instruction.** Not investigated — they may
|
||
be absent phases, a different record variant, or a decode edge.
|
||
|
||
|
||
## 🔴 What `entry_a` really is — NOT an entry point
|
||
|
||
Disassembling the three Stage-02 `entry_a` targets shows **opcodes 0x19 and
|
||
0x1A**, and the dispatcher's table has 25 entries (`cmplwi 0x18`). Those are not
|
||
instructions at all:
|
||
|
||
```
|
||
014848: 00000819 tag 19 00000019 int 25
|
||
014850: 00000819 tag 19 00002B20 int
|
||
014858: 0000081A tag 1A 00000000 float 0.0
|
||
014860: 00000819 tag 19 00000005 int 5
|
||
014868: 00000819 tag 19 00002B88 int
|
||
014870: 0000081A tag 1A 3F000000 float 0.5
|
||
```
|
||
|
||
Each phase region **ends with a trailing DATA table** of 8-byte typed records —
|
||
tag `0x19` = int, tag `0x1A` = IEEE float — and `entry_a` is where it starts.
|
||
|
||
**Confirmed across the disc: in 44 of 44 phases, the first offset whose opcode
|
||
exceeds 0x18 is exactly that phase's `entry_a`. Zero exceptions.** Only two tags
|
||
ever appear: 1 394 × `0x19` and 675 × `0x1A`.
|
||
|
||
So the record is `0x1883, base, size, 0, code_end, force_end_handler` — one
|
||
boundary and one entry.
|
||
|
||
🟡 The table's contents are **not decoded**. Its int values do land on the
|
||
instruction stream more often than chance (46/51 vs 29.5 %), but **0 of them are
|
||
unreached run-starts** — so this is not what starts the unreachable code either.
|
||
|
||
## ✅ And the decoder was reading that data as code
|
||
|
||
`isl.linear_offsets` was decoding all **2 069** of those records as instructions,
|
||
1.23 % of the stream. Fixed by stopping each phase's walk at its boundary:
|
||
|
||
| | before | after |
|
||
|---|---|---|
|
||
| decoded instructions | 168 251 | **166 182** = 168 251 − 2 069 |
|
||
| records with opcode > 0x18 | 2 069 | **0** |
|
||
| **call sites covered** | 25 705 / 25 705 | **25 705 / 25 705** |
|
||
| exits unreachable | 0 | 0 |
|
||
| conditions with unknown LHS | 400 | 400 |
|
||
|
||
⚠️ **The first attempt at that fix destroyed 36 % of the stream** — 168 251 →
|
||
107 596, exits 0 → 74 — because `linear_offsets` is one global walk from the
|
||
first phase base, so stopping at phase 1's table lost every later phase. It has
|
||
to *skip* the region and resume at the next base. A count moving hard in the
|
||
wrong direction is the same signal as one that will not move. |