summary_lower_l7.md 2.7 KB

Lower phase — L7 (the flip): status and plan (2026-10-05)

Branch ast-stage-c. L7 = "flip: lower from the AST instead of inline; delete the inline emit + Fwd* machinery".

Why L7 is not incremental

The flip makes Lower the sole emitter. The obstacle is that QbeGen holds one session state, used by the inline emit during parse; a per-unit Lower emit would be clobbered by the next unit's inline emit. So the flip is a big-bang: either remove/suppress the grammar's 533 QbeGen.* call sites, or give QbeGen two states — neither is a byte-verifiable step.

The pragmatic path is therefore a session re-emit: collect every unit's AST and re-emit the whole session with Lower after parsing. That is byte-comparable against the legacy session image and becomes the flip once the inline emit is removed.

Started (d30abfd, tag v3-lower7-scaffold)

  • Lower.LowerSession/LowerOneUnit/MaterializeGlobals.
  • Driver (compiler.frm) collects GetUnit() per file and calls Lower.LowerSession under -lower.
  • SymTab.Materialize makes a unit's own VAR/CONST visible in globScope, so GlobalRef resolves "<unit>_<name>" at session end (the unit scopes are closed by then).
  • Removed Lower.Reset from the M2 root so the owned tables persist across a session.

Still scaffolding (inline emit untouched); suite 200/200, FIXPOINT OK (3,401,129 bytes).

Gaps found (all fixable, all required for the flip)

  1. DefUnit builds no AST. Its ConstBlock/TypeBlock/VarBlock/ ProcHeading loop never AstAppends, so a definition module's AST has no decls; its proc headings (which consume backend temps) cannot be replayed. Fix: append to astDecl in DefUnit.
  2. Owned-table size. MaxProc=64 / MaxSym=512 are sized for one unit; a full-session re-emit needs every module's procs/vars. Growing them grows the compiler image (watch the 4 MiB sessBuf).
  3. Nested-module globals. QualNode(outer, name) does not see a nested scope's non-exported globals; ReenterGlobals re-enters them but with curMod = -1 (empty mod), so GlobalRef falls back to $name instead of $<outer>_<name>.
  4. Definition-module proc replay must emit only the heading (BeginFunc/FuncParam/AbortFunc), like LowerMethodHeadings.
  5. Possibly more, revealed once a full session is compared.

Plan

  1. Fix (1) and (4); grow tables (2) within the image budget.
  2. Compare Lower.LowerSession's image against the legacy session image for the compiler's own sources (the real test).
  3. Fix the remaining gaps until the session image byte-matches.
  4. Flip: remove the inline emit; keep Lower per unit; the fixpoint becomes the gate.