|
@@ -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.
|