|
|
@@ -0,0 +1,113 @@
|
|
|
+# Lower phase — L7 complete (2026-10-08)
|
|
|
+
|
|
|
+Branch **`ast-stage-c`**. Tag **`v3-lower7-complete`**.
|
|
|
+
|
|
|
+This closes L7: **`Lower` is the only emitter**, the inline emit that
|
|
|
+could be removed cleanly is gone, the `-lower` scaffold is retired, and
|
|
|
+dead code is swept. Verified with `compiler/run_tests.sh`
|
|
|
+(**181/181**) and `bootstrap/fixpoint.sh` (**FIXPOINT OK**) after every
|
|
|
+step.
|
|
|
+
|
|
|
+## What happened, in order
|
|
|
+
|
|
|
+### 1. The switch is flipped (`857c221`)
|
|
|
+
|
|
|
+The driver (`compiler/src/compiler.frm`) always runs the per-unit
|
|
|
+`Lower` emit (`BeginSession`/`BeginUnit`/`LowerUnitNow`/`EndSession`);
|
|
|
+the grammar's inline emit runs suppressed (`SetNoEmit`) and is
|
|
|
+discarded. A no-op flip, because `Lower` had been verified
|
|
|
+byte-identical to the legacy inline emit on every single-file test and
|
|
|
+every session.
|
|
|
+
|
|
|
+### 2. Inline emit deleted from statements and declarations
|
|
|
+
|
|
|
+`e5830b2` (builtin statements), `ce37247` (control flow), `acc4e91`
|
|
|
+(declarations/lifecycle). Not mechanical: `TopLoop`/`PushLoop`/
|
|
|
+`TopWith`/`PushWith`/`IsImm`/`Fold2`/`LocFull`/`ConstInt` are checks or
|
|
|
+parser state and 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`).
|
|
|
+`QbeGen.AddrOfVal` scans the whole VAR-actual note ring, and
|
|
|
+`RestoreSession` restored `nn` but never cleared the ring — so the
|
|
|
+grammar's suppressed parse-time `NoteAddr` entries survived into
|
|
|
+`Lower` and a stale key could false-match. Fix: clear the ring in
|
|
|
+`RestoreSession`. Output-neutral on `Showcase11`; corrected some latent
|
|
|
+resolutions in the compiler's own image.
|
|
|
+
|
|
|
+### 4. Dead-code sweep
|
|
|
+
|
|
|
+`d730e80` (the `Can*` family, `LowerSession`/`LowerUnit`,
|
|
|
+`SetLower`/`lowerRequested`), `e269828` (QbeGen orphans), `241c2c9`
|
|
|
+(SymTab/QbeGen orphans), `b0ef2bf` (`AST.TxtLen`/`SetKind`),
|
|
|
+`b4d9e25` (post-decoupling orphans: `SetOutName`, `FwdDesignator`,
|
|
|
+`FwdAddrOper`, `IsExternal`, `MethUid`, `FieldOwner`). A tree-wide
|
|
|
+scan (tests included) now reports **0** unreferenced procs.
|
|
|
+
|
|
|
+### 5. Value/emit decoupling
|
|
|
+
|
|
|
+The expression value is also the front-end constant evaluator
|
|
|
+(`Expr`'s `q` feeds `SetSymVal`/`NoteConstVal`/`IsImm`/`ConstInt`), so
|
|
|
+it could not just be dropped. Runtime results are marked with the
|
|
|
+non-constant sentinel `"@"` (which `IsImm`/`ConstInt` reject);
|
|
|
+constant folding (`NegFold`/`Fold2`/`StrFold`) and every check stay.
|
|
|
+
|
|
|
+- `6001af6` `SimExpr`, `5fb26e7` `Term`, `4f2afa0` `Expr`,
|
|
|
+ `d469c78` `Fact` runtime builtins/calls.
|
|
|
+- `90d2529` the **coupled change**: `Design`/`Fact`/`ArgList`/`ActParam`
|
|
|
+ together, dropping the `NoteAddr`/`AddrOfVal` note chain from the
|
|
|
+ grammar (kept for `Lower`) and replacing VAR-actual addressability
|
|
|
+ with an AST-kind check (`NkDesignator`, or `NkStrLit`).
|
|
|
+- `0667290` `Design`/`ResultComp`, `0ebe92e` assignment, `f59b784`
|
|
|
+ remaining runtime value ops, `02f2526` `ProcHeading`'s output.
|
|
|
+
|
|
|
+### 6. `-lower` retired (`bcb93a5`)
|
|
|
+
|
|
|
+With one emitter, `-lower` no longer changed what was emitted — only
|
|
|
+the image name for a byte-compare that compared `Lower` against itself.
|
|
|
+`IsLowerParam`/`lowerTest`/`EndSession`'s `testSuffix` and the 23
|
|
|
+`lower_ok`/`lower_ok_files` cases are gone; the covered programs are
|
|
|
+still exercised by the `expect_run`/session cases. Suite 204 → 181.
|
|
|
+
|
|
|
+## Traps worth remembering
|
|
|
+
|
|
|
+- **`ArgList` alone can't be decoupled:** dropping its `CallBegin`
|
|
|
+ (fewer `NewTemp`s) shifts the note-ring keys and breaks calls — 75
|
|
|
+ suite failures. `Design`→`Fact`→`ArgList`→`ActParam` is one unit.
|
|
|
+- **An empty `(. .)` action** in `ProcDecl` generated a bare `;` empty
|
|
|
+ statement that **gm2 accepts but the V3 self-host grammar rejects** —
|
|
|
+ the suite passed while the fixpoint failed.
|
|
|
+
|
|
|
+## What remains
|
|
|
+
|
|
|
+The grammar's remaining `QbeGen` calls are not removable emit:
|
|
|
+
|
|
|
+- the **value layer** (`CopyOp`, `IsImm`, `IntStr`, `Fold2`, `Norm*`,
|
|
|
+ `Conv*`, `CharVal`, `StrFold`/`StrEq`, `CapQ`/`AbsQ`/`NotQ`,
|
|
|
+ `UStrLen`) — computes constants and the `q` `Lower.NoteConstVal`
|
|
|
+ consumes; and
|
|
|
+- the **parser-state / lifecycle** (`SetModule`, `BeginFunc`/
|
|
|
+ `FuncParam`/`EndFunc`/`AbortFunc`, `PushWith`/`PopWith`/`PushLoop`/
|
|
|
+ `PopLoop`, `TopWith`/`TopLoop`/`LocFull`, `DeclStr`/`DeclUStr`,
|
|
|
+ `SetLit`/`Ctor*`).
|
|
|
+
|
|
|
+Deleting `SaveSession`/`RestoreSession`/`SetNoEmit` (the last item)
|
|
|
+requires the grammar to stop writing entirely, which means
|
|
|
+reimplementing the parameter-scope bookkeeping (`FuncParam` needs
|
|
|
+`BeginFunc`'s `nPar` reset) and the `WITH`/`EXIT` stacks outside
|
|
|
+`QbeGen` — a reimplementation, not cleanup.
|
|
|
+
|
|
|
+## Fixpoint sizes across the work
|
|
|
+
|
|
|
+| step | bytes |
|
|
|
+|---|---|
|
|
|
+| flip | 3,553,701 |
|
|
|
+| statements + declarations + bug fix | 3,538,557 |
|
|
|
+| dead-code sweep | 3,420,733 |
|
|
|
+| decoupling (expr layer) | 3,406,951 |
|
|
|
+| decoupling complete (Design/Fact/calls/assignment/ProcHeading) | 3,377,935 |
|
|
|
+| `-lower` retired + orphan cleanup | 3,367,634 |
|
|
|
+
|
|
|
+~186 KB smaller than at the flip, all green.
|