Pārlūkot izejas kodu

docs: session summary — the L7 flip landed and the emit decoupling started

Eric Streit 3 dienas atpakaļ
vecāks
revīzija
367b64656d
1 mainītis faili ar 120 papildinājumiem un 0 dzēšanām
  1. 120 0
      docs/summary_lower_l7_flip.md

+ 120 - 0
docs/summary_lower_l7_flip.md

@@ -0,0 +1,120 @@
+# Lower phase — L7 flip landed (2026-10-08)
+
+Branch **`ast-stage-c`**.  Tag **`v3-lower7-flip`**.
+
+This session did three things: (1) **flipped the emitter** so `Lower` is
+the only active emitter, (2) **deleted the inline emit** from the
+statement and declaration productions, and (3) **started the value/emit
+decoupling** so expression emit could go too — in the process it found
+and fixed a **real latent bug** in the VAR-actual note ring.
+
+Everything is verified with `compiler/run_tests.sh` (**204/204**) and
+`bootstrap/fixpoint.sh` (**FIXPOINT OK**) after every step.
+
+## 1. The switch is flipped (`857c221`)
+
+The driver (`compiler/src/compiler.frm`) now always runs the per-unit
+`Lower` emit: `BeginSession`/`BeginUnit`/`LowerUnitNow`/`EndSession`.
+The grammar's inline emit is still present but runs suppressed
+(`SetNoEmit`) and is discarded.  `-lower` is now test-only — it does not
+change *what* is emitted, only names the image `<mod>L.ssa` for the
+byte-compare harness.
+
+This was a no-op flip because `Lower` had already been verified
+byte-identical to the legacy inline emit on every single-file test and
+every session.
+
+FIXPOINT OK, 3,553,701 bytes.
+
+## 2. Inline emit deleted from statements and declarations
+
+| commit | production group |
+|---|---|
+| `e5830b2` | builtin statements (`EXIT`, `INCL`/`EXCL`, `INC`/`DEC`, `NEW`, `DISPOSE`) |
+| `ce37247` | control flow (`IF`/`WHILE`/`REPEAT`/`LOOP`/`FOR`/`CASE`), `RETURN`, `HALT` |
+| `acc4e91` | declarations/lifecycle (`DeclVar`/`DeclConst`, module/impl/nested/class `BeginInit`/`EndInit`/`BeginBody`/`EndModule`, `FlushPend`, `FwdPatch`) |
+
+Not mechanical: many `QbeGen.*` calls are semantic queries or parser
+state, not emit (`TopLoop`/`PushLoop`/`PopLoop`, `TopWith`/`PushWith`,
+`IsImm`/`Fold2`/`NormInt`, `LocFull`, `ConstInt`, …) and must stay.
+
+## 3. A real bug found and fixed (`7de78bb`)
+
+Removing the grammar's `QbeGen.DeclVar` exposed a latent mis-resolution:
+`Strings.Replace`'s `src` VAR actual became `$Strings_nl`, so `Showcase11`
+no longer linked.
+
+Root cause: **`QbeGen.AddrOfVal` scans the whole 256-entry `nVal`/`nAddr`
+VAR-actual note ring, and `RestoreSession` restored `nn` but never
+cleared the ring.**  The grammar's suppressed parse-time `NoteAddr`
+entries survived into `Lower`; their keys are temps that restart per
+function, so a stale entry could false-match.  Removing `DeclVar` (fewer
+`AllocLocal`/`NewTemp` calls) shifted those keys and exposed it.
+
+Fix: `RestoreSession` clears the ring.  `Lower` re-notes its own VAR
+actuals, so an empty ring is correct.  The fix is output-neutral on
+`Showcase11` and corrected some latent resolutions in the compiler's own
+image.
+
+## 4. Dead-code sweep (tree-wide, tests included)
+
+| commit | removed |
+|---|---|
+| `d730e80` | `LowerSession`, `LowerUnit`, the whole `Can*` family, `SetLower`/`lowerRequested` |
+| `e269828` | `QbeGen`'s `CloseModule`, `FwdPatch`, `FwdElemPatch`, `Remark` |
+| `241c2c9` | `SymTab`'s `CurModule`/`CurUnit`/`ProcDepth`/`ParamName`/`ModDefined`/`ModImplemented`/`Qual*`/`NestArray`/`NewSub`/`SetElemCheck`/`SetFor`/`UnaryCheck`/`FwdVarKind`, `QbeGen.StrLen` |
+| `b0ef2bf` | `AST.TxtLen`, `AST.SetKind` (`AST.AddChild` stays: `t_ast.mod` uses it) |
+
+A scan over `src/`, `tests/`, `runtime/`, `stdlib/`, `tools/` now reports
+no unreferenced procs in `AST`/`SymTab`/`QbeGen`/`Lower`.
+
+Still needed until the inline emit is gone:
+`SaveSession`/`RestoreSession`/`SetNoEmit`, and
+`MaterializeGlobals`/`MaterializeReplace` (live, from `LowerOneUnit`).
+
+## 5. Value/emit decoupling (started)
+
+The expression value is also the front-end's constant value (`Expr`'s `q`
+feeds `SymTab.SetSymVal`/`Lower.NoteConstVal` and `IsImm`/`ConstInt`), so
+it cannot simply be dropped.  The decoupling marks runtime results with a
+**non-constant sentinel `"@"`** (`IsImm`/`ConstInt` reject it), keeps
+constant folding (`NegFold`/`Fold2`/`StrFold`) and every check.
+
+| commit | production |
+|---|---|
+| `6001af6` | `SimExpr` (unary `-`, `OR`, UString/CHAR concat, set binops, arithmetic) |
+| `5fb26e7` | `Term` (`AND`, set intersection, `*` `/` `DIV` `MOD`) |
+| `4f2afa0` | `Expr` relation (`=`,`#`,`<`,`<=`,`>`,`>=`,`IN`) |
+| `d469c78` | `Fact`'s always-runtime branches (ResultComp `ElemLoad`, zero-arg calls, `ADR`, `SHIFT`/`ROTATE`, open-array `HIGH`/`LEN`, `CHR8` range check) |
+
+Constant-producing builtins (fixed-array `HIGH`/`LEN`, `SIZE`/`TSIZE`,
+`MAX`/`MIN`, `ORD`/`CHR`/`VAL`, …) keep their folding paths.
+
+## The remaining coupled change
+
+`Design` → `Fact` → `ArgList` → `ActParam` plus the `NoteAddr`/
+`AddrOfVal` chain must move **as one unit**: `Fact` records
+`NoteAddr(q, qd)`/`AddrOf(qn, qa)` and `ActParam` recovers the VAR-actual
+address with `AddrOfVal(qe, qa)`, and the note key is the actual's
+*emitted* value.  Verified: dropping `ArgList`'s `CallBegin` alone (fewer
+`NewTemp`s) shifts the keys and breaks calls (75 suite failures).  To
+finish: `Design` emits nothing (literal for a constant, `"@"` otherwise),
+`Fact` drops the notes, `ActParam` replaces `AddrOfVal` with an
+AST-kind addressability check and drops `CallArg`, then `ArgList` drops
+`CallBegin`/`CallEnd`; afterwards `NoteAddr`/`AddrOfVal`/`AddrOf` in
+`QbeGen` are dead.
+
+Then: retire the `-lower` test flag and the now-degenerate byte-compare
+tests, and delete `SaveSession`/`RestoreSession`/`SetNoEmit`.
+
+## Fixpoint sizes across the session
+
+| step | bytes |
+|---|---|
+| flip | 3,553,701 |
+| statements + declarations + bug fix | 3,538,557 |
+| dead-code sweep | 3,420,733 |
+| value/emit decoupling (expr layer) | 3,406,951 |
+
+The functional goal — **`Lower` is the only emitter** — is met.  The rest
+is architecture/cleanliness.