re: recover ISL conditions by CFG dataflow instead of a linear walk
The linear walk's 10% unknown was a floor imposed by the method: a block entered only
by a branch has a well-defined state, just not one a straight-line pass can see.
tools/re-capture/isl_cfg.py replaces it with a worklist fixpoint that joins each
block's state over its ACTUAL predecessors -- a value survives only if every
predecessor agrees.
Over all 28 stages:
instructions reached by the CFG 85.0%
condition sites, unknown LHS 756 (10.00%) -> 402 (5.32%)
of those, never reached at all 389
joined away (predecessors disagree) 13
both resolve but DISAGREE 161 <- linear walk was wrong here
Those 161 are on top of the 889 the previous jmp fix caught.
Two zero-results on the way, both my own bug, both caught because the number looked
wrong rather than because a test failed:
* The first CFG run reached only 36% of instructions and made things WORSE (35%
unknown). Cause: the phase bases reach almost nothing. Most routines are
COROUTINES the engine starts from its trigger queue, with no static predecessor,
so every start_coroutine target has to be seeded as an entry.
* That seeding then found ZERO entries in a file with 216 start_coroutine calls,
because the target is staged in TWO steps -- special[0] = imm, then
local[0] = special[0] -- and I matched only the direct-immediate form.
Reachability went 36% -> 64% -> 85% as each was fixed.
The 389 still unreached are an honest limit rather than a gap: nothing in the bytecode
starts them; they are entered from the trigger queue at phase+272, by data rather than
code, so no purely static analysis reaches them.
isl_report.py conditions now uses isl_cfg; calls and phase-ends regenerate
byte-identical. Stage 02 unknowns drop from 71 to 25.
This commit is contained in:
@@ -47,7 +47,7 @@ the stack, then reports each compare with its branch:
|
||||
| | all 28 stages |
|
||||
|---|---|
|
||||
| condition sites | **7 563** |
|
||||
| **LHS honestly unresolved** | **756 — 10.0 %** |
|
||||
| **LHS honestly unresolved** | **402 — 5.3 %** (CFG dataflow; the linear walk left 756) |
|
||||
| RHS is a plain number | 7 544 — 99.7 % |
|
||||
|
||||
🔴 **The first version of this table claimed 0.0 % unresolved. That was wrong** —
|
||||
@@ -182,4 +182,47 @@ word@+4`), so the CFG is available; the analysis is not written.
|
||||
|
||||
**Method note worth keeping:** when the same defect appears twice, fix the class.
|
||||
Patching `end_coroutine` alone left 22× more bad sites in place than it removed,
|
||||
and only another impossible-looking output exposed them.
|
||||
and only another impossible-looking output exposed them.
|
||||
|
||||
## ✅ Replaced by a CFG dataflow fixpoint — `isl_cfg.py`
|
||||
|
||||
The linear walk's honest 10 % unknown was a floor imposed by the method, not by
|
||||
the data: a block entered only by a branch has *a* well-defined state, just not
|
||||
one a straight-line pass can see. So the walk is gone, replaced by a worklist
|
||||
fixpoint that joins each block's state over its **actual predecessors** — a value
|
||||
survives only if every predecessor agrees.
|
||||
|
||||
| over all 28 stages | linear walk | CFG dataflow |
|
||||
|---|---|---|
|
||||
| instructions reached | (all, but with stale state) | **85.0 %** |
|
||||
| condition sites with an unknown LHS | 756 — 10.00 % | **402 — 5.32 %** |
|
||||
| of those, never reached at all | — | 389 |
|
||||
| joined away (predecessors genuinely disagree) | — | **13** |
|
||||
| **sites where both resolve but DISAGREE** | — | **161** |
|
||||
|
||||
Those 161 are 161 more places the linear walk reported a confident wrong answer,
|
||||
on top of the 889 the `jmp` fix caught.
|
||||
|
||||
### ⚠️ Two zero-results that were both my bug
|
||||
|
||||
The first CFG run reached only **36 %** of instructions and made things *worse*
|
||||
— 35 % unknown against the walk's 10 %. Two causes, and each surfaced as a
|
||||
suspiciously round zero:
|
||||
|
||||
1. **The phase bases reach almost nothing.** Most routines are **coroutines** the
|
||||
engine starts from its trigger queue, so they have no static predecessor at
|
||||
all. They must be seeded from every `start_coroutine` target.
|
||||
2. **The seeding found ZERO entries in a file with 216 `start_coroutine` calls.**
|
||||
The target is staged in *two* steps — `special[0] = imm`, then
|
||||
`local[0] = special[0]` — and I matched only the direct-immediate form.
|
||||
|
||||
Reachability went 36 % → 64 % → **85 %** as each was fixed. The lesson is the one
|
||||
this corpus keeps re-teaching: *a count that does not move when it should is the
|
||||
bug reporting itself.* Both times I checked because the number looked wrong, not
|
||||
because a test failed.
|
||||
|
||||
### 🟡 The 389 that remain are a real limit, not a gap
|
||||
|
||||
Nothing in the bytecode starts them. They are entered from the **trigger queue at
|
||||
`phase+272`** — by data, not by code — so no purely static analysis reaches them.
|
||||
Resolving those needs the trigger table's contents, which is a separate question.
|
||||
|
||||
Reference in New Issue
Block a user